mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-31 03:08:40 +02:00
Compare commits
+18
-6
@@ -32,6 +32,8 @@
|
||||
- '**/GameIndex.*'
|
||||
'Installer | Package':
|
||||
- 'build.sh'
|
||||
'Translations':
|
||||
- 'pcsx2-qt/Translations/*'
|
||||
|
||||
# Tools / Features
|
||||
'Debugger':
|
||||
@@ -45,6 +47,9 @@
|
||||
'TAS Functionality':
|
||||
- 'pcsx2/Recording/*'
|
||||
- 'pcsx2/Recording/**/*'
|
||||
'RetroAchievements':
|
||||
- 'pcsx2/Frontend/Achievements.*'
|
||||
- 'pcsx2/Achievements.*'
|
||||
|
||||
# Emulation Components
|
||||
'Counters':
|
||||
@@ -64,21 +69,31 @@
|
||||
'GS':
|
||||
- 'pcsx2/GS/*'
|
||||
- 'pcsx2/GS/**/*'
|
||||
- 'bin/resources/shaders/*'
|
||||
- 'bin/resources/shaders/**/*'
|
||||
'GS: Direct3D 11':
|
||||
- 'pcsx2/GS/Renderers/DX11/*'
|
||||
- 'pcsx2/GS/Renderers/DX11/**/*'
|
||||
- 'bin/resources/shaders/dx11/*'
|
||||
- 'bin/resources/shaders/dx11/**/*'
|
||||
'GS: Direct3D 12':
|
||||
- 'pcsx2/GS/Renderers/DX12/*'
|
||||
- 'pcsx2/GS/Renderers/DX12/**/*'
|
||||
- 'bin/resources/shaders/dx11/*'
|
||||
- 'bin/resources/shaders/dx11/**/*'
|
||||
'GS: Hardware':
|
||||
- 'pcsx2/GS/Renderers/HW/*'
|
||||
- 'pcsx2/GS/Renderers/HW/**/*'
|
||||
'GS: OpenGL':
|
||||
- 'pcsx2/GS/Renderers/OpenGL/*'
|
||||
- 'pcsx2/GS/Renderers/OpenGL/**/*'
|
||||
- 'bin/resources/shaders/opengl/*'
|
||||
- 'bin/resources/shaders/opengl/**/*'
|
||||
'GS: Vulkan':
|
||||
- 'pcsx2/GS/Renderers/Vulkan/*'
|
||||
- 'pcsx2/GS/Renderers/Vulkan/**/*'
|
||||
- 'bin/resources/shaders/vulkan/*'
|
||||
- 'bin/resources/shaders/vulkan/**/*'
|
||||
'GS: Metal':
|
||||
- 'pcsx2/GS/Renderers/Metal/*'
|
||||
- 'pcsx2/GS/Renderers/Metal/**/*'
|
||||
@@ -102,12 +117,9 @@
|
||||
'Memory Card':
|
||||
- 'pcsx2/gui/MemoryCard*'
|
||||
- 'pcsx2/gui/**/MemoryCard*'
|
||||
'PAD: Linux/Mac':
|
||||
- 'pcsx2/PAD/Linux/*'
|
||||
- 'pcsx2/PAD/Linux/**/*'
|
||||
'PAD: Windows':
|
||||
- 'pcsx2/PAD/Windows/*'
|
||||
- 'pcsx2/PAD/Windows/**/*'
|
||||
'PAD':
|
||||
- 'pcsx2/PAD/*'
|
||||
- 'pcsx2/PAD/**/*'
|
||||
'SPU2':
|
||||
- 'pcsx2/SPU2/*'
|
||||
- 'pcsx2/SPU2/**/*'
|
||||
|
||||
@@ -9,25 +9,12 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build_linux_qt_sse4:
|
||||
build_linux_qt:
|
||||
name: "AppImage"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt SSE4"
|
||||
jobName: "Qt"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
simd: "SSE4"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
build_linux_qt_avx2:
|
||||
name: "AppImage"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt AVX2"
|
||||
detail: ""
|
||||
compiler: clang
|
||||
cmakeflags: "-DARCH_FLAG=-march=haswell"
|
||||
simd: "AVX2"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
@@ -28,10 +28,6 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
simd:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
cheats_url:
|
||||
required: false
|
||||
type: string
|
||||
@@ -63,7 +59,6 @@ jobs:
|
||||
OS: linux
|
||||
GUI_FRAMEWORK: QT
|
||||
ARCH: ${{ inputs.platform }}
|
||||
SIMD: ${{ inputs.simd }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
@@ -79,8 +74,8 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
|
||||
|
||||
- name: Install Packages
|
||||
env:
|
||||
|
||||
@@ -49,7 +49,6 @@ jobs:
|
||||
OS: macos
|
||||
GUI_FRAMEWORK: ${{ inputs.gui }}
|
||||
ARCH: ${{ inputs.platform }}
|
||||
SIMD: ''
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
|
||||
@@ -8,32 +8,28 @@ on:
|
||||
jobs:
|
||||
# Build Everything
|
||||
# Linux
|
||||
build_linux_qt_sse4:
|
||||
build_linux_qt:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Linux - AppImage SSE4"
|
||||
name: "Linux"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
simd: "SSE4"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
build_linux_qt_avx2:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Linux - AppImage AVX2"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt"
|
||||
detail: ""
|
||||
compiler: clang
|
||||
cmakeflags: "-DARCH_FLAG=-march=haswell"
|
||||
simd: "AVX2"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
# Windows
|
||||
build_windows_qt:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Windows"
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: Qt
|
||||
configuration: CMake
|
||||
buildSystem: cmake
|
||||
secrets: inherit
|
||||
|
||||
build_qt_sse4:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Windows - SSE4"
|
||||
@@ -67,8 +63,8 @@ jobs:
|
||||
upload_artifacts:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
needs:
|
||||
- build_linux_qt_sse4
|
||||
- build_linux_qt_avx2
|
||||
- build_linux_qt
|
||||
- build_windows_qt
|
||||
- build_qt_sse4
|
||||
- build_qt_avx2
|
||||
- build_macos_qt
|
||||
|
||||
@@ -21,7 +21,7 @@ NAME=""
|
||||
|
||||
if [ "${OS}" == "macos" ]; then
|
||||
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}"
|
||||
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") || ("$OS" == "linux" && "$GUI_FRAMEWORK" == "QT") ]]; then
|
||||
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
|
||||
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}-${SIMD}"
|
||||
else
|
||||
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}"
|
||||
|
||||
+716
-301
File diff suppressed because it is too large
Load Diff
@@ -383,7 +383,7 @@
|
||||
0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
|
||||
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b7,righttrigger:b2,platform:Windows,
|
||||
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
|
||||
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -407,7 +407,6 @@
|
||||
03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
|
||||
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
|
||||
@@ -484,8 +483,8 @@
|
||||
030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,
|
||||
030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
|
||||
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
|
||||
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
|
||||
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
|
||||
030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
|
||||
@@ -542,8 +541,9 @@
|
||||
030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
|
||||
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,x:b0,y:b5,back:b2,guide:b10,start:b3,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpleft:b14,dpdown:b13,dpright:b15,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,
|
||||
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -882,7 +882,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
|
||||
0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,x:b6,y:b8,start:b18,leftshoulder:b10,rightshoulder:b12,dpup:b24,dpdown:b28,dpleft:b30,dpright:b26,lefttrigger:b14,righttrigger:b4,platform:Mac OS X,
|
||||
030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
|
||||
03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X,
|
||||
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
@@ -899,6 +899,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000d620000011a7000010050000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,platform:Mac OS X,
|
||||
030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X,
|
||||
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
@@ -945,6 +946,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X,
|
||||
03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000006f0e00008701000005010000,Rock Candy Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X,
|
||||
03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X,
|
||||
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
|
||||
@@ -1131,6 +1133,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -1241,10 +1244,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b7,righttrigger:b2,platform:Linux,
|
||||
030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
|
||||
0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
|
||||
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
|
||||
@@ -1327,7 +1330,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00008501000011010000,PDP Nintendo Switch Fightpad Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00008701000011010000,PDP Rock Nintendo Switch Candy Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000006f0e00000901000011010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1385,6 +1387,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
|
||||
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1416,6 +1419,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00008701000011010000,Rock Candy Switch Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1445,6 +1449,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
|
||||
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#define PS_FST 0
|
||||
#define PS_WMS 0
|
||||
#define PS_WMT 0
|
||||
#define PS_ADJS 0
|
||||
#define PS_ADJT 0
|
||||
#define PS_AEM_FMT FMT_32
|
||||
#define PS_AEM 0
|
||||
#define PS_TFX 0
|
||||
@@ -42,7 +44,6 @@
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_INVALID_TEX0 0
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP 0
|
||||
@@ -158,10 +159,10 @@ cbuffer cb1
|
||||
float2 TA;
|
||||
float MaxDepthPS;
|
||||
float Af;
|
||||
uint4 MskFix;
|
||||
uint4 FbMask;
|
||||
float4 HalfTexel;
|
||||
float4 MinMax;
|
||||
float4 STRange;
|
||||
int4 ChannelShuffle;
|
||||
float2 TC_OffsetHack;
|
||||
float2 STScale;
|
||||
@@ -183,7 +184,20 @@ float4 sample_c(float2 uv, float uv_w)
|
||||
// As of 2018 this issue is still present.
|
||||
uv = (trunc(uv * WH.zw) + float2(0.5, 0.5)) / WH.zw;
|
||||
}
|
||||
#if !PS_ADJS && !PS_ADJT
|
||||
uv *= STScale;
|
||||
#else
|
||||
#if PS_ADJS
|
||||
uv.x = (uv.x - STRange.x) * STRange.z;
|
||||
#else
|
||||
uv.x = uv.x * STScale.x;
|
||||
#endif
|
||||
#if PS_ADJT
|
||||
uv.y = (uv.y - STRange.y) * STRange.w;
|
||||
#else
|
||||
uv.y = uv.y * STScale.y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return Texture.Sample(TextureSampler, uv);
|
||||
@@ -218,12 +232,7 @@ float4 sample_p_norm(float u)
|
||||
|
||||
float4 clamp_wrap_uv(float4 uv)
|
||||
{
|
||||
float4 tex_size;
|
||||
|
||||
if (PS_INVALID_TEX0 == 1)
|
||||
tex_size = WH.zwzw;
|
||||
else
|
||||
tex_size = WH.xyxy;
|
||||
float4 tex_size = WH.xyxy;
|
||||
|
||||
if(PS_WMS == PS_WMT)
|
||||
{
|
||||
@@ -238,7 +247,7 @@ float4 clamp_wrap_uv(float4 uv)
|
||||
// textures. Fixes Xenosaga's hair issue.
|
||||
uv = frac(uv);
|
||||
#endif
|
||||
uv = (float4)(((uint4)(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
|
||||
uv = (float4)(((uint4)(uv * tex_size) & asuint(MinMax.xyxy)) | asuint(MinMax.zwzw)) / tex_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -252,7 +261,7 @@ float4 clamp_wrap_uv(float4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.xz = frac(uv.xz);
|
||||
#endif
|
||||
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
|
||||
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & asuint(MinMax.xx)) | asuint(MinMax.zz)) / tex_size.xx;
|
||||
}
|
||||
if(PS_WMT == 2)
|
||||
{
|
||||
@@ -263,7 +272,7 @@ float4 clamp_wrap_uv(float4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.yw = frac(uv.yw);
|
||||
#endif
|
||||
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
|
||||
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & asuint(MinMax.yy)) | asuint(MinMax.ww)) / tex_size.yy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +362,7 @@ float4 fetch_c(int2 uv)
|
||||
|
||||
int2 clamp_wrap_uv_depth(int2 uv)
|
||||
{
|
||||
int4 mask = (int4)MskFix << 4;
|
||||
int4 mask = asint(MinMax) << 4;
|
||||
if (PS_WMS == PS_WMT)
|
||||
{
|
||||
if (PS_WMS == 2)
|
||||
@@ -676,11 +685,7 @@ float4 fog(float4 c, float f)
|
||||
|
||||
float4 ps_color(PS_INPUT input)
|
||||
{
|
||||
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
|
||||
// Re-normalize coordinate from invalid GS to corrected texture size
|
||||
float2 st = (input.t.xy * WH.xy) / (input.t.w * WH.zw);
|
||||
float2 st_int = (input.ti.zw * WH.xy) / (input.t.w * WH.zw);
|
||||
#elif PS_FST == 0
|
||||
#if PS_FST == 0
|
||||
float2 st = input.t.xy / input.t.w;
|
||||
float2 st_int = input.ti.zw / input.t.w;
|
||||
#else
|
||||
|
||||
@@ -75,13 +75,12 @@ layout(std140, binding = 0) uniform cb21
|
||||
float MaxDepthPS;
|
||||
float Af;
|
||||
|
||||
uvec4 MskFix;
|
||||
|
||||
uvec4 FbMask;
|
||||
|
||||
vec4 HalfTexel;
|
||||
|
||||
vec4 MinMax;
|
||||
vec4 STRange;
|
||||
|
||||
ivec4 ChannelShuffle;
|
||||
|
||||
@@ -92,11 +91,6 @@ layout(std140, binding = 0) uniform cb21
|
||||
};
|
||||
#endif
|
||||
|
||||
//layout(std140, binding = 22) uniform cb22
|
||||
//{
|
||||
// vec4 rt_size;
|
||||
//};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Default Sampler
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -109,7 +109,20 @@ vec4 sample_c(vec2 uv)
|
||||
// As of 2018 this issue is still present.
|
||||
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
|
||||
#endif
|
||||
uv *= STScale;
|
||||
#if !PS_ADJS && !PS_ADJT
|
||||
uv *= STScale;
|
||||
#else
|
||||
#if PS_ADJS
|
||||
uv.x = (uv.x - STRange.x) * STRange.z;
|
||||
#else
|
||||
uv.x = uv.x * STScale.x;
|
||||
#endif
|
||||
#if PS_ADJT
|
||||
uv.y = (uv.y - STRange.y) * STRange.w;
|
||||
#else
|
||||
uv.y = uv.y * STScale.y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return texture(TextureSampler, uv);
|
||||
@@ -146,11 +159,7 @@ vec4 sample_p_norm(float u)
|
||||
vec4 clamp_wrap_uv(vec4 uv)
|
||||
{
|
||||
vec4 uv_out = uv;
|
||||
#if PS_INVALID_TEX0 == 1
|
||||
vec4 tex_size = WH.zwzw;
|
||||
#else
|
||||
vec4 tex_size = WH.xyxy;
|
||||
#endif
|
||||
|
||||
#if PS_WMS == PS_WMT
|
||||
|
||||
@@ -162,7 +171,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
// textures. Fixes Xenosaga's hair issue.
|
||||
uv = fract(uv);
|
||||
#endif
|
||||
uv_out = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
|
||||
uv_out = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
|
||||
#endif
|
||||
|
||||
#else // PS_WMS != PS_WMT
|
||||
@@ -174,7 +183,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.xz = fract(uv.xz);
|
||||
#endif
|
||||
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
|
||||
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -185,7 +194,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.yw = fract(uv.yw);
|
||||
#endif
|
||||
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
|
||||
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -227,7 +236,7 @@ uvec4 sample_4_index(vec4 uv)
|
||||
|
||||
#if PS_PAL_FMT == 1
|
||||
// 4HL
|
||||
return i & 0xFu
|
||||
return i & 0xFu;
|
||||
#elif PS_PAL_FMT == 2
|
||||
// 4HH
|
||||
return i >> 4u;
|
||||
@@ -288,7 +297,7 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
|
||||
// Keep the full precision
|
||||
// It allow to multiply the ScalingFactor before the 1/16 coeff
|
||||
ivec4 mask = ivec4(MskFix) << 4;
|
||||
ivec4 mask = floatBitsToInt(MinMax) << 4;
|
||||
|
||||
#if PS_WMS == PS_WMT
|
||||
|
||||
@@ -591,11 +600,7 @@ void fog(inout vec4 C, float f)
|
||||
vec4 ps_color()
|
||||
{
|
||||
//FIXME: maybe we can set gl_Position.w = q in VS
|
||||
#if (PS_FST == 0) && (PS_INVALID_TEX0 == 1)
|
||||
// Re-normalize coordinate from invalid GS to corrected texture size
|
||||
vec2 st = (PSin.t_float.xy * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
|
||||
vec2 st_int = (PSin.t_int.zw * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
|
||||
#elif (PS_FST == 0)
|
||||
#if (PS_FST == 0)
|
||||
vec2 st = PSin.t_float.xy / vec2(PSin.t_float.w);
|
||||
vec2 st_int = PSin.t_int.zw / vec2(PSin.t_float.w);
|
||||
#else
|
||||
|
||||
@@ -312,6 +312,8 @@ void main()
|
||||
#define PS_FST 0
|
||||
#define PS_WMS 0
|
||||
#define PS_WMT 0
|
||||
#define PS_ADJS 0
|
||||
#define PS_ADJT 0
|
||||
#define PS_FMT FMT_32
|
||||
#define PS_AEM 0
|
||||
#define PS_TFX 0
|
||||
@@ -332,7 +334,6 @@ void main()
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_INVALID_TEX0 0
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP 0
|
||||
@@ -361,10 +362,10 @@ layout(std140, set = 0, binding = 1) uniform cb1
|
||||
vec2 TA;
|
||||
float MaxDepthPS;
|
||||
float Af;
|
||||
uvec4 MskFix;
|
||||
uvec4 FbMask;
|
||||
vec4 HalfTexel;
|
||||
vec4 MinMax;
|
||||
vec4 STRange;
|
||||
ivec4 ChannelShuffle;
|
||||
vec2 TC_OffsetHack;
|
||||
vec2 STScale;
|
||||
@@ -420,7 +421,20 @@ vec4 sample_c(vec2 uv)
|
||||
// As of 2018 this issue is still present.
|
||||
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
|
||||
#endif
|
||||
#if !PS_ADJS && !PS_ADJT
|
||||
uv *= STScale;
|
||||
#else
|
||||
#if PS_ADJS
|
||||
uv.x = (uv.x - STRange.x) * STRange.z;
|
||||
#else
|
||||
uv.x = uv.x * STScale.x;
|
||||
#endif
|
||||
#if PS_ADJT
|
||||
uv.y = (uv.y - STRange.y) * STRange.w;
|
||||
#else
|
||||
uv.y = uv.y * STScale.y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return texture(Texture, uv);
|
||||
@@ -455,13 +469,7 @@ vec4 sample_p_norm(float u)
|
||||
|
||||
vec4 clamp_wrap_uv(vec4 uv)
|
||||
{
|
||||
vec4 tex_size;
|
||||
|
||||
#if PS_INVALID_TEX0
|
||||
tex_size = WH.zwzw;
|
||||
#else
|
||||
tex_size = WH.xyxy;
|
||||
#endif
|
||||
vec4 tex_size = WH.xyxy;
|
||||
|
||||
#if PS_WMS == PS_WMT
|
||||
{
|
||||
@@ -476,7 +484,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
// textures. Fixes Xenosaga's hair issue.
|
||||
uv = fract(uv);
|
||||
#endif
|
||||
uv = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
|
||||
uv = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -491,7 +499,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.xz = fract(uv.xz);
|
||||
#endif
|
||||
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
|
||||
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
|
||||
}
|
||||
#endif
|
||||
#if PS_WMT == 2
|
||||
@@ -503,7 +511,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.yw = fract(uv.yw);
|
||||
#endif
|
||||
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
|
||||
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -534,14 +542,14 @@ uvec4 sample_4_index(vec4 uv)
|
||||
c.w = sample_c(uv.zw).a;
|
||||
|
||||
// Denormalize value
|
||||
uvec4 i = uvec4(c * 255.0f + 0.5f);
|
||||
uvec4 i = uvec4(c * 255.5f);
|
||||
|
||||
#if PS_PAL_FMT == 1
|
||||
// 4HL
|
||||
c = i & 0xFu;
|
||||
return i & 0xFu;
|
||||
#elif PS_PAL_FMT == 2
|
||||
// 4HH
|
||||
c = i >> 4u;
|
||||
return i >> 4u;
|
||||
#else
|
||||
// 8
|
||||
return i;
|
||||
@@ -590,7 +598,7 @@ vec4 fetch_c(ivec2 uv)
|
||||
|
||||
ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
{
|
||||
ivec4 mask = ivec4(MskFix << 4);
|
||||
ivec4 mask = floatBitsToInt(MinMax) << 4;
|
||||
#if (PS_WMS == PS_WMT)
|
||||
{
|
||||
#if (PS_WMS == 2)
|
||||
@@ -907,11 +915,7 @@ vec4 fog(vec4 c, float f)
|
||||
|
||||
vec4 ps_color()
|
||||
{
|
||||
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
|
||||
// Re-normalize coordinate from invalid GS to corrected texture size
|
||||
vec2 st = (vsIn.t.xy * WH.xy) / (vsIn.t.w * WH.zw);
|
||||
vec2 st_int = (vsIn.ti.zw * WH.xy) / (vsIn.t.w * WH.zw);
|
||||
#elif PS_FST == 0
|
||||
#if PS_FST == 0
|
||||
vec2 st = vsIn.t.xy / vsIn.t.w;
|
||||
vec2 st_int = vsIn.ti.zw / vsIn.t.w;
|
||||
#else
|
||||
|
||||
@@ -10,16 +10,14 @@ add_library(common)
|
||||
# x86emitter sources
|
||||
target_sources(common PRIVATE
|
||||
AlignedMalloc.cpp
|
||||
VirtualMemory.cpp
|
||||
EventSource.inl
|
||||
SafeArray.inl
|
||||
Console.cpp
|
||||
CrashHandler.cpp
|
||||
DynamicLibrary.cpp
|
||||
EventSource.cpp
|
||||
Exceptions.cpp
|
||||
FastJmp.cpp
|
||||
FileSystem.cpp
|
||||
General.cpp
|
||||
Image.cpp
|
||||
HTTPDownloader.cpp
|
||||
MemorySettingsInterface.cpp
|
||||
@@ -71,7 +69,6 @@ target_sources(common PRIVATE
|
||||
DynamicLibrary.h
|
||||
Easing.h
|
||||
EnumOps.h
|
||||
EventSource.h
|
||||
Exceptions.h
|
||||
FastJmp.h
|
||||
FileSystem.h
|
||||
@@ -88,7 +85,6 @@ target_sources(common PRIVATE
|
||||
MD5Digest.h
|
||||
MRCHelpers.h
|
||||
Path.h
|
||||
PageFaultSource.h
|
||||
PrecompiledHeader.h
|
||||
ProgressCallback.h
|
||||
ReadbackSpinManager.h
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventSource< template EvtType >
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template <typename ListenerType>
|
||||
class EventSource
|
||||
{
|
||||
public:
|
||||
typedef typename ListenerType::EvtParams EvtParams;
|
||||
typedef typename std::list<ListenerType*> ListenerList;
|
||||
typedef typename ListenerList::iterator ListenerIterator;
|
||||
|
||||
protected:
|
||||
typedef typename ListenerList::const_iterator ConstIterator;
|
||||
|
||||
ListenerList m_listeners;
|
||||
|
||||
// This is a cached copy of the listener list used to handle standard dispatching, which
|
||||
// allows for self-modification of the EventSource's listener list by the listeners.
|
||||
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
||||
ListenerList m_cache_copy;
|
||||
bool m_cache_valid;
|
||||
|
||||
std::mutex m_listeners_lock;
|
||||
|
||||
public:
|
||||
EventSource()
|
||||
{
|
||||
m_cache_valid = false;
|
||||
}
|
||||
|
||||
virtual ~EventSource() = default;
|
||||
|
||||
virtual ListenerIterator Add(ListenerType& listener);
|
||||
virtual void Remove(ListenerType& listener);
|
||||
virtual void Remove(const ListenerIterator& listenerHandle);
|
||||
|
||||
void Add(ListenerType* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Add(*listener);
|
||||
}
|
||||
|
||||
void Remove(ListenerType* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Remove(*listener);
|
||||
}
|
||||
|
||||
void Dispatch(const EvtParams& params);
|
||||
|
||||
protected:
|
||||
virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
|
||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventDispatcher
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base interface for EventListeners. It allows the listeners to do
|
||||
// customized dispatching of several event types into "user friendly" function overrides.
|
||||
//
|
||||
template <typename EvtParams>
|
||||
class IEventDispatcher
|
||||
{
|
||||
protected:
|
||||
IEventDispatcher() {}
|
||||
|
||||
public:
|
||||
virtual ~IEventDispatcher() = default;
|
||||
virtual void DispatchEvent(const EvtParams& params) = 0;
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/Console.h"
|
||||
|
||||
template <typename ListenerType>
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
|
||||
{
|
||||
std::unique_lock locker(m_listeners_lock);
|
||||
|
||||
// Check for duplicates before adding the event.
|
||||
if (IsDebugBuild)
|
||||
{
|
||||
ListenerIterator iter = m_listeners.begin();
|
||||
while (iter != m_listeners.end())
|
||||
{
|
||||
if ((*iter) == &listener)
|
||||
return iter;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
return _AddFast_without_lock(listener);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Remove(ListenerType& listener)
|
||||
{
|
||||
std::unique_lock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove(&listener);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
|
||||
{
|
||||
std::unique_lock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.erase(listenerHandle);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.push_front(&listener);
|
||||
return m_listeners.begin();
|
||||
}
|
||||
|
||||
|
||||
template <typename ListenerType>
|
||||
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
|
||||
{
|
||||
while (iter != iend)
|
||||
{
|
||||
try
|
||||
{
|
||||
(*iter)->DispatchEvent(evtparams);
|
||||
}
|
||||
catch (Exception::RuntimeError& ex)
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
pxFailDev(("Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage()).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Ignoring runtime error thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
|
||||
}
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
ex.DiagMsg() = "Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||
throw;
|
||||
}
|
||||
Console.Error("Ignoring non-runtime BaseException thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
|
||||
{
|
||||
if (!m_cache_valid)
|
||||
{
|
||||
m_cache_copy = m_listeners;
|
||||
m_cache_valid = true;
|
||||
}
|
||||
|
||||
if (m_cache_copy.empty())
|
||||
return;
|
||||
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
|
||||
}
|
||||
@@ -74,33 +74,6 @@ namespace Exception
|
||||
virtual BaseException* Clone() const = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Ps2Generic Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
||||
//
|
||||
// Implementation note: does not derive from BaseException, so that we can use different
|
||||
// catch block hierarchies to handle them (if needed).
|
||||
//
|
||||
// Translation Note: Currently these exceptions are never translated. English/diagnostic
|
||||
// format only. :)
|
||||
//
|
||||
class Ps2Generic
|
||||
{
|
||||
protected:
|
||||
std::string m_message; // a "detailed" message of what disastrous thing has occurred!
|
||||
|
||||
public:
|
||||
virtual ~Ps2Generic() = default;
|
||||
|
||||
virtual u32 GetPc() const = 0;
|
||||
virtual bool IsDelaySlot() const = 0;
|
||||
virtual std::string& Message() { return m_message; }
|
||||
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual Ps2Generic* Clone() const = 0;
|
||||
};
|
||||
|
||||
// Some helper macros for defining the standard constructors of internationalized constructors
|
||||
// Parameters:
|
||||
// classname - Yeah, the name of this class being defined. :)
|
||||
|
||||
@@ -60,7 +60,10 @@ namespace GL
|
||||
GLint info_log_length = 0;
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
|
||||
if (status == GL_FALSE || info_log_length > 0)
|
||||
// Log will create a new line when there are no warnings so let's set a minimum log length of 1.
|
||||
constexpr int info_log_min_length = 1;
|
||||
|
||||
if (status == GL_FALSE || info_log_length > info_log_min_length)
|
||||
{
|
||||
std::string info_log;
|
||||
info_log.resize(info_log_length + 1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -14,7 +14,26 @@
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "EventSource.h"
|
||||
#include "EventSource.inl"
|
||||
#include "General.h"
|
||||
|
||||
//template class EventSource< int >;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PageProtectionMode (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string PageProtectionMode::ToString() const
|
||||
{
|
||||
std::string modeStr;
|
||||
|
||||
if (m_read)
|
||||
modeStr += "Read";
|
||||
if (m_write)
|
||||
modeStr += "Write";
|
||||
if (m_exec)
|
||||
modeStr += "Exec";
|
||||
|
||||
if (modeStr.empty())
|
||||
return "NoAccess";
|
||||
if (modeStr.length() <= 5)
|
||||
modeStr += "Only";
|
||||
|
||||
return modeStr;
|
||||
}
|
||||
@@ -116,6 +116,14 @@ static __fi PageProtectionMode PageAccess_Any()
|
||||
return PageProtectionMode().All();
|
||||
}
|
||||
|
||||
struct PageFaultInfo
|
||||
{
|
||||
uptr pc;
|
||||
uptr addr;
|
||||
};
|
||||
|
||||
using PageFaultHandler = bool(*)(const PageFaultInfo& info);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// HostSys
|
||||
// --------------------------------------------------------------------------------------
|
||||
@@ -141,6 +149,12 @@ namespace HostSys
|
||||
extern void DestroySharedMemory(void* ptr);
|
||||
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
|
||||
extern void UnmapSharedMemory(void* baseaddr, size_t size);
|
||||
|
||||
/// Installs the specified page fault handler. Only one handler can be active at once.
|
||||
bool InstallPageFaultHandler(PageFaultHandler handler);
|
||||
|
||||
/// Removes the page fault handler. handler is only specified to check against the active callback.
|
||||
void RemovePageFaultHandler(PageFaultHandler handler);
|
||||
}
|
||||
|
||||
class SharedMemoryMappingArea
|
||||
|
||||
+90
-38
@@ -21,13 +21,15 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include "common/Align.h"
|
||||
#include "common/PageFaultSource.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/General.h"
|
||||
|
||||
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
|
||||
// the same thing.
|
||||
@@ -44,34 +46,57 @@
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
extern void SignalExit(int sig);
|
||||
static std::recursive_mutex s_exception_handler_mutex;
|
||||
static PageFaultHandler s_exception_handler_callback;
|
||||
static bool s_in_exception_handler;
|
||||
|
||||
static const uptr m_pagemask = getpagesize() - 1;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#ifdef __APPLE__
|
||||
static struct sigaction s_old_sigbus_action;
|
||||
#else
|
||||
static struct sigaction s_old_sigsegv_action;
|
||||
#endif
|
||||
|
||||
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
const struct sigaction& sa = s_old_sigbus_action;
|
||||
#else
|
||||
const struct sigaction& sa = s_old_sigsegv_action;
|
||||
#endif
|
||||
|
||||
if (sa.sa_flags & SA_SIGINFO)
|
||||
{
|
||||
sa.sa_sigaction(signal, siginfo, ctx);
|
||||
}
|
||||
else if (sa.sa_handler == SIG_DFL)
|
||||
{
|
||||
// Re-raising the signal would just queue it, and since we'd restore the handler back to us,
|
||||
// we'd end up right back here again. So just abort, because that's probably what it'd do anyway.
|
||||
abort();
|
||||
}
|
||||
else if (sa.sa_handler != SIG_IGN)
|
||||
{
|
||||
sa.sa_handler(signal);
|
||||
}
|
||||
}
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||
{
|
||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||
// process, but the handler is executed by the thread that caused the exception.
|
||||
// Executing the handler concurrently from multiple threads wouldn't go down well.
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
|
||||
// Prevent recursive exception filtering.
|
||||
if (s_in_exception_handler)
|
||||
{
|
||||
CallExistingSignalHandler(signal, siginfo, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||
// from the context of the current thread and stackframe. So long as the thread is not
|
||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||
// be safe even on the main thread.
|
||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||
// signals)
|
||||
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs, assertions, file logs,
|
||||
// or just about anything else useful. However, that's really only a concern if the signal
|
||||
// occurred within those functions. The logging which we do only happens when the exception
|
||||
// occurred within JIT code.
|
||||
|
||||
#if defined(__APPLE__) && defined(__x86_64__)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
||||
@@ -81,35 +106,62 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||
void* const exception_pc = nullptr;
|
||||
#endif
|
||||
|
||||
// Note: This signal can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
std::unique_lock lock(PageFault_Mutex);
|
||||
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)siginfo->si_addr & ~__pagemask};
|
||||
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)siginfo->si_addr & ~m_pagemask));
|
||||
s_in_exception_handler = true;
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if (Source_PageFault->WasHandled())
|
||||
const bool handled = s_exception_handler_callback(pfi);
|
||||
|
||||
s_in_exception_handler = false;
|
||||
|
||||
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV).
|
||||
if (handled)
|
||||
return;
|
||||
|
||||
std::fprintf(stderr, "Unhandled page fault @ 0x%08x", siginfo->si_addr);
|
||||
pxFailRel("Unhandled page fault");
|
||||
// Call old signal handler, which will likely dump core.
|
||||
CallExistingSignalHandler(signal, siginfo, ctx);
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
|
||||
if (!s_exception_handler_callback)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
#if defined(__APPLE__)
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
sigaction(SIGBUS, &sa, &s_old_sigbus_action);
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
#ifdef __APPLE__
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
|
||||
return false;
|
||||
#else
|
||||
sigaction(SIGSEGV, &sa, &s_old_sigsegv_action);
|
||||
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
s_exception_handler_callback = handler;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
|
||||
"Not removing the same handler previously registered.");
|
||||
if (!s_exception_handler_callback)
|
||||
return;
|
||||
|
||||
s_exception_handler_callback = nullptr;
|
||||
|
||||
struct sigaction sa;
|
||||
#ifdef __APPLE__
|
||||
sigaction(SIGBUS, &s_old_sigbus_action, &sa);
|
||||
#else
|
||||
sigaction(SIGSEGV, &s_old_sigsegv_action, &sa);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,9 @@ namespace Vulkan
|
||||
m_provoking_vertex = {};
|
||||
m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
|
||||
|
||||
m_line_rasterization_state = {};
|
||||
m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
|
||||
|
||||
// set defaults
|
||||
SetNoCullRasterizationState();
|
||||
SetNoDepthTestState();
|
||||
@@ -255,7 +258,17 @@ namespace Vulkan
|
||||
m_ci.pRasterizationState = &m_rasterization_state;
|
||||
}
|
||||
|
||||
void GraphicsPipelineBuilder::SetLineWidth(float width) { m_rasterization_state.lineWidth = width; }
|
||||
void GraphicsPipelineBuilder::SetLineWidth(float width)
|
||||
{
|
||||
m_rasterization_state.lineWidth = width;
|
||||
}
|
||||
|
||||
void GraphicsPipelineBuilder::SetLineRasterizationMode(VkLineRasterizationModeEXT mode)
|
||||
{
|
||||
Util::AddPointerToChain(&m_rasterization_state, &m_line_rasterization_state);
|
||||
|
||||
m_line_rasterization_state.lineRasterizationMode = mode;
|
||||
}
|
||||
|
||||
void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples, bool per_sample_shading)
|
||||
{
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace Vulkan
|
||||
|
||||
void SetRasterizationState(VkPolygonMode polygon_mode, VkCullModeFlags cull_mode, VkFrontFace front_face);
|
||||
void SetLineWidth(float width);
|
||||
void SetLineRasterizationMode(VkLineRasterizationModeEXT mode);
|
||||
void SetMultisamples(u32 multisamples, bool per_sample_shading);
|
||||
void SetNoCullRasterizationState();
|
||||
|
||||
@@ -157,6 +158,7 @@ namespace Vulkan
|
||||
VkPipelineMultisampleStateCreateInfo m_multisample_state;
|
||||
|
||||
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex;
|
||||
VkPipelineRasterizationLineStateCreateInfoEXT m_line_rasterization_state;
|
||||
};
|
||||
|
||||
class ComputePipelineBuilder
|
||||
|
||||
@@ -458,6 +458,8 @@ namespace Vulkan
|
||||
SupportsExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps =
|
||||
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_line_rasterization =
|
||||
SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_driver_properties =
|
||||
SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access =
|
||||
@@ -654,12 +656,19 @@ namespace Vulkan
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
{
|
||||
provoking_vertex_feature.provokingVertexLast = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &provoking_vertex_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
{
|
||||
line_rasterization_feature.bresenhamLines = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &line_rasterization_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
{
|
||||
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
|
||||
@@ -724,12 +733,16 @@ namespace Vulkan
|
||||
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
Util::AddPointerToChain(&features2, &provoking_vertex_features);
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
Util::AddPointerToChain(&features2, &line_rasterization_feature);
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
Util::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
|
||||
@@ -739,6 +752,7 @@ namespace Vulkan
|
||||
// confirm we actually support it
|
||||
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
|
||||
|
||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
void** pNext = &properties2.pNext;
|
||||
@@ -789,6 +803,8 @@ namespace Vulkan
|
||||
|
||||
Console.WriteLn("VK_EXT_provoking_vertex is %s",
|
||||
m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_line_rasterization is %s",
|
||||
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_ARM_rasterization_order_attachment_access is %s",
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace Vulkan
|
||||
bool vk_ext_provoking_vertex : 1;
|
||||
bool vk_ext_memory_budget : 1;
|
||||
bool vk_ext_calibrated_timestamps : 1;
|
||||
bool vk_ext_line_rasterization : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_arm_rasterization_order_attachment_access : 1;
|
||||
bool vk_khr_fragment_shader_barycentric : 1;
|
||||
|
||||
@@ -17,60 +17,78 @@
|
||||
|
||||
#include "common/Align.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/PageFaultSource.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/AlignedMalloc.h"
|
||||
#include "fmt/core.h"
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
{
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
#include <mutex>
|
||||
|
||||
#if defined(_M_AMD64)
|
||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
|
||||
#else
|
||||
void* const exception_pc = nullptr;
|
||||
#endif
|
||||
|
||||
// Note: This exception can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
std::unique_lock lock(PageFault_Mutex);
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]));
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
static std::recursive_mutex s_exception_handler_mutex;
|
||||
static PageFaultHandler s_exception_handler_callback;
|
||||
static void* s_exception_handler_handle;
|
||||
static bool s_in_exception_handler;
|
||||
|
||||
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
{
|
||||
// Prevent recursive exception filtering by catching the exception from the filter here.
|
||||
// In the event that the filter causes an access violation (happened during shutdown
|
||||
// because Source_PageFault was deallocated), this will allow the debugger to catch the
|
||||
// exception.
|
||||
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
||||
// work but I don't fully understand why some do and some don't.
|
||||
__try
|
||||
{
|
||||
return DoSysPageFaultExceptionFilter(eps);
|
||||
}
|
||||
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
||||
{
|
||||
// Executing the handler concurrently from multiple threads wouldn't go down well.
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
|
||||
// Prevent recursive exception filtering.
|
||||
if (s_in_exception_handler)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// Only interested in page faults.
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
|
||||
|
||||
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]};
|
||||
|
||||
s_in_exception_handler = true;
|
||||
|
||||
const bool handled = s_exception_handler_callback(pfi);
|
||||
|
||||
s_in_exception_handler = false;
|
||||
|
||||
return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
|
||||
if (!s_exception_handler_handle)
|
||||
{
|
||||
s_exception_handler_handle = AddVectoredExceptionHandler(TRUE, SysPageFaultExceptionFilter);
|
||||
if (!s_exception_handler_handle)
|
||||
return false;
|
||||
}
|
||||
|
||||
s_exception_handler_callback = handler;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
|
||||
"Not removing the same handler previously registered.");
|
||||
s_exception_handler_callback = nullptr;
|
||||
|
||||
if (s_exception_handler_handle)
|
||||
{
|
||||
RemoveVectoredExceptionHandler(s_exception_handler_handle);
|
||||
s_exception_handler_handle = {};
|
||||
}
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
|
||||
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
|
||||
{
|
||||
DWORD winmode = PAGE_NOACCESS;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<ClCompile Include="FastJmp.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="General.cpp" />
|
||||
<ClCompile Include="GL\Context.cpp" />
|
||||
<ClCompile Include="GL\ContextWGL.cpp" />
|
||||
<ClCompile Include="GL\Program.cpp" />
|
||||
@@ -90,7 +91,6 @@
|
||||
<ClCompile Include="StringUtil.cpp" />
|
||||
<ClCompile Include="SettingsWrapper.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="VirtualMemory.cpp" />
|
||||
<ClCompile Include="Vulkan\vk_mem_alloc.cpp" />
|
||||
<ClCompile Include="Vulkan\Builders.cpp" />
|
||||
<ClCompile Include="Vulkan\Context.cpp" />
|
||||
@@ -130,7 +130,6 @@
|
||||
<ClCompile Include="emitter\WinCpuDetect.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="EventSource.inl" />
|
||||
<MASM Include="FastJmp.asm" />
|
||||
<None Include="Vulkan\EntryPoints.inl" />
|
||||
</ItemGroup>
|
||||
@@ -178,7 +177,6 @@
|
||||
<ClInclude Include="SettingsWrapper.h" />
|
||||
<ClInclude Include="Assertions.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="EventSource.h" />
|
||||
<ClInclude Include="Exceptions.h" />
|
||||
<ClInclude Include="General.h" />
|
||||
<ClInclude Include="MathUtils.h" />
|
||||
|
||||
@@ -67,9 +67,6 @@
|
||||
<ClCompile Include="emitter\simd.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualMemory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\WinCpuDetect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -211,6 +208,7 @@
|
||||
<ClCompile Include="WAVWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="General.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AlignedMalloc.h">
|
||||
@@ -234,9 +232,6 @@
|
||||
<ClInclude Include="emitter\implement\dwshift.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EventSource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Exceptions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -532,9 +527,6 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="EventSource.inl">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="Vulkan\EntryPoints.inl">
|
||||
<Filter>Source Files\Vulkan</Filter>
|
||||
</None>
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/emitter/tools.h"
|
||||
|
||||
// warning: suggest braces around initialization of subobject [-Wmissing-braces]
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
#endif
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
const xImplAVX_Move xVMOVAPS = {0x00, 0x28, 0x29};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
files:
|
||||
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
|
||||
translation: '/pcsx2-qt/Translations/pcsx2-qt_%two_letters_code%.ts'
|
||||
+44
-11
@@ -48,6 +48,7 @@
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
|
||||
@@ -79,6 +80,7 @@ static std::optional<bool> s_use_window;
|
||||
|
||||
// Owned by the GS thread.
|
||||
static u32 s_dump_frame_number = 0;
|
||||
static u32 s_loop_number = s_loop_count;
|
||||
|
||||
bool GSRunner::InitializeConfig()
|
||||
{
|
||||
@@ -102,6 +104,13 @@ bool GSRunner::InitializeConfig()
|
||||
// we don't need any sound output
|
||||
si.SetStringValue("SPU2/Output", "OutputModule", "nullout");
|
||||
|
||||
// none of the bindings are going to resolve to anything
|
||||
PAD::ClearPortBindings(si, 0);
|
||||
si.ClearSection("Hotkeys");
|
||||
|
||||
// make sure any gamesettings inis in your tree don't get loaded
|
||||
si.SetBoolValue("EmuCore", "EnablePerGameSettings", false);
|
||||
|
||||
// force logging
|
||||
si.SetBoolValue("Logging", "EnableSystemConsole", true);
|
||||
si.SetBoolValue("Logging", "EnableTimestamps", true);
|
||||
@@ -273,13 +282,15 @@ void Host::ReleaseHostDisplay(bool clear_state)
|
||||
|
||||
bool Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
// when we wrap around, don't race other files
|
||||
GSJoinSnapshotThreads();
|
||||
|
||||
// queue dumping of this frame
|
||||
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
if (s_loop_number == 0)
|
||||
{
|
||||
// when we wrap around, don't race other files
|
||||
GSJoinSnapshotThreads();
|
||||
|
||||
// queue dumping of this frame
|
||||
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
}
|
||||
if (g_host_display->BeginPresent(frame_skip))
|
||||
return true;
|
||||
|
||||
@@ -351,10 +362,6 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
|
||||
{
|
||||
pxFailRel("Not implemented");
|
||||
@@ -377,7 +384,7 @@ void Host::SetFullscreen(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestExit(bool save_state_if_running)
|
||||
void Host::RequestExit(bool allow_confirm)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -523,6 +530,29 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", static_cast<int>(type));
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-renderhacks"))
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks", true);
|
||||
|
||||
if(str.find("af") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_AutoFlush", true);
|
||||
if (str.find("cpufb") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_CPU_FB_Conversion", true);
|
||||
if (str.find("dds") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableDepthSupport", true);
|
||||
if (str.find("dpi") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisablePartialInvalidation", true);
|
||||
if (str.find("dsf") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableSafeFeatures", true);
|
||||
if (str.find("tinrt") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_TextureInsideRt", true);
|
||||
if (str.find("plf") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "preload_frame_with_gs_data", true);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-logfile"))
|
||||
{
|
||||
const char* logfile = argv[++i];
|
||||
@@ -631,6 +661,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// apply new settings (e.g. pick up renderer change)
|
||||
VMManager::ApplySettings();
|
||||
GSDumpReplayer::SetIsDumpRunner(true);
|
||||
|
||||
if (VMManager::Initialize(params))
|
||||
{
|
||||
@@ -644,6 +675,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
InputManager::CloseSources();
|
||||
VMManager::Internal::ReleaseMemory();
|
||||
VMManager::Internal::ReleaseGlobals();
|
||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
|
||||
GSRunner::DestroyPlatformWindow();
|
||||
|
||||
@@ -654,6 +686,7 @@ void Host::CPUThreadVSync()
|
||||
{
|
||||
// update GS thread copy of frame number
|
||||
GetMTGS().RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
|
||||
GetMTGS().RunOnGSThread([loop_number = GSDumpReplayer::GetLoopCount()]() { s_loop_number = loop_number; });
|
||||
|
||||
// process any window messages (but we shouldn't really have any)
|
||||
GSRunner::PumpPlatformMessages();
|
||||
|
||||
@@ -16,7 +16,7 @@ def is_gs_path(path):
|
||||
return False
|
||||
|
||||
|
||||
def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
|
||||
def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath):
|
||||
args = [runner]
|
||||
gsname = Path(gspath).name
|
||||
while gsname.rfind('.') >= 0:
|
||||
@@ -28,6 +28,10 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
|
||||
|
||||
if renderer is not None:
|
||||
args.extend(["-renderer", renderer])
|
||||
|
||||
if renderhacks is not None:
|
||||
args.extend(["-renderhacks", renderhacks])
|
||||
|
||||
args.extend(["-dumpdir", real_dumpdir])
|
||||
args.extend(["-logfile", os.path.join(real_dumpdir, "emulog.txt")])
|
||||
|
||||
@@ -46,7 +50,7 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
|
||||
subprocess.run(args)
|
||||
|
||||
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, renderhacks, parallel=1):
|
||||
paths = glob.glob(gsdir + "/*.*", recursive=True)
|
||||
gamepaths = list(filter(is_gs_path, paths))
|
||||
|
||||
@@ -57,10 +61,10 @@ def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
|
||||
|
||||
if parallel <= 1:
|
||||
for game in gamepaths:
|
||||
run_regression_test(runner, dumpdir, renderer, parallel, game)
|
||||
run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, game)
|
||||
else:
|
||||
print("Processing %u games on %u processors" % (len(gamepaths), parallel))
|
||||
func = partial(run_regression_test, runner, dumpdir, renderer, parallel)
|
||||
func = partial(run_regression_test, runner, dumpdir, renderer, parallel, renderhacks)
|
||||
pool = multiprocessing.Pool(parallel)
|
||||
pool.map(func, gamepaths)
|
||||
pool.close()
|
||||
@@ -76,10 +80,11 @@ if __name__ == "__main__":
|
||||
parser.add_argument("-dumpdir", action="store", required=True, help="Base directory to dump frames to")
|
||||
parser.add_argument("-renderer", action="store", required=False, help="Renderer to use")
|
||||
parser.add_argument("-parallel", action="store", type=int, default=1, help="Number of proceeses to run")
|
||||
parser.add_argument("-renderhacks", action="store", required=False, help="Enable HW Renering hacks")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.parallel):
|
||||
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.renderhacks, args.parallel):
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
@@ -465,7 +465,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
|
||||
else if (result == 1)
|
||||
{
|
||||
// updater started. since we're a modal on the main window, we have to queue this.
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, true));
|
||||
done(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,18 +107,15 @@ QVariant StackModel::headerData(int section, Qt::Orientation orientation, int ro
|
||||
|
||||
void StackModel::refreshData()
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_IOP)
|
||||
return;
|
||||
|
||||
// Hopefully in the near future we can get a stack frame for
|
||||
// each thread
|
||||
beginResetModel();
|
||||
for (const auto& thread : getEEThreads())
|
||||
for (const auto& thread : m_cpu.GetThreadList())
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
{
|
||||
m_stackFrames = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
|
||||
thread.data.entry_init, thread.data.stack);
|
||||
thread->EntryPoint(), thread->StackTop());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,7 @@ ThreadModel::ThreadModel(DebugInterface& cpu, QObject* parent)
|
||||
|
||||
int ThreadModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_EE)
|
||||
return getEEThreads().size();
|
||||
else
|
||||
return 0;
|
||||
return m_cpu.GetThreadList().size();
|
||||
}
|
||||
|
||||
int ThreadModel::columnCount(const QModelIndex&) const
|
||||
@@ -40,66 +37,65 @@ int ThreadModel::columnCount(const QModelIndex&) const
|
||||
|
||||
QVariant ThreadModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
const auto threads = m_cpu.GetThreadList();
|
||||
auto* const thread = threads.at(index.row()).get();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
const auto thread = getEEThreads().at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case ThreadModel::ID:
|
||||
return thread.tid;
|
||||
return thread->TID();
|
||||
case ThreadModel::PC:
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
return QtUtils::FilledQStringFromValue(m_cpu.getPC(), 16);
|
||||
else
|
||||
return QtUtils::FilledQStringFromValue(thread.data.entry, 16);
|
||||
|
||||
return QtUtils::FilledQStringFromValue(thread->PC(), 16);
|
||||
}
|
||||
case ThreadModel::ENTRY:
|
||||
return QtUtils::FilledQStringFromValue(thread.data.entry_init, 16);
|
||||
return QtUtils::FilledQStringFromValue(thread->EntryPoint(), 16);
|
||||
case ThreadModel::PRIORITY:
|
||||
return QString::number(thread.data.currentPriority);
|
||||
return QString::number(thread->Priority());
|
||||
case ThreadModel::STATE:
|
||||
{
|
||||
const auto& state = ThreadStateStrings.find(thread.data.status);
|
||||
const auto& state = ThreadStateStrings.find(thread->Status());
|
||||
if (state != ThreadStateStrings.end())
|
||||
return state->second;
|
||||
else
|
||||
return tr("INVALID");
|
||||
|
||||
return tr("INVALID");
|
||||
}
|
||||
case ThreadModel::WAIT_TYPE:
|
||||
{
|
||||
const auto& waitType = ThreadWaitStrings.find(thread.data.waitType);
|
||||
const auto& waitType = ThreadWaitStrings.find(thread->Wait());
|
||||
if (waitType != ThreadWaitStrings.end())
|
||||
return waitType->second;
|
||||
else
|
||||
return tr("INVALID");
|
||||
|
||||
return tr("INVALID");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
{
|
||||
const auto thread = getEEThreads().at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case ThreadModel::ID:
|
||||
return thread.tid;
|
||||
return thread->TID();
|
||||
case ThreadModel::PC:
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
return m_cpu.getPC();
|
||||
else
|
||||
return thread.data.entry;
|
||||
|
||||
return thread->PC();
|
||||
}
|
||||
case ThreadModel::ENTRY:
|
||||
return thread.data.entry_init;
|
||||
return thread->EntryPoint();
|
||||
case ThreadModel::PRIORITY:
|
||||
return thread.data.currentPriority;
|
||||
return thread->Priority();
|
||||
case ThreadModel::STATE:
|
||||
return thread.data.status;
|
||||
return static_cast<u32>(thread->Status());
|
||||
case ThreadModel::WAIT_TYPE:
|
||||
return thread.data.waitType;
|
||||
return static_cast<u32>(thread->Wait());
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@@ -48,19 +48,27 @@ public:
|
||||
void refreshData();
|
||||
|
||||
private:
|
||||
const std::map<int, QString> ThreadStateStrings{
|
||||
{THS_BAD, tr("BAD")},
|
||||
{THS_RUN, tr("RUN")},
|
||||
{THS_READY, tr("READY")},
|
||||
{THS_WAIT, tr("WAIT")},
|
||||
{THS_SUSPEND, tr("SUSPEND")},
|
||||
{THS_WAIT_SUSPEND, tr("WAIT SUSPEND")},
|
||||
{THS_DORMANT, tr("DORMANT")}};
|
||||
const std::map<ThreadStatus, QString> ThreadStateStrings{
|
||||
{ThreadStatus::THS_BAD, tr("BAD")},
|
||||
{ThreadStatus::THS_RUN, tr("RUN")},
|
||||
{ThreadStatus::THS_READY, tr("READY")},
|
||||
{ThreadStatus::THS_WAIT, tr("WAIT")},
|
||||
{ThreadStatus::THS_SUSPEND, tr("SUSPEND")},
|
||||
{ThreadStatus::THS_WAIT_SUSPEND, tr("WAIT SUSPEND")},
|
||||
{ThreadStatus::THS_DORMANT, tr("DORMANT")},
|
||||
};
|
||||
|
||||
const std::map<int, QString> ThreadWaitStrings{
|
||||
{WAIT_NONE, tr("NONE")},
|
||||
{WAIT_WAKEUP_REQ, tr("WAKEUP REQUEST")},
|
||||
{WAIT_SEMA, tr("SEMAPHORE")}};
|
||||
const std::map<WaitState, QString> ThreadWaitStrings{
|
||||
{WaitState::NONE, tr("NONE")},
|
||||
{WaitState::WAKEUP_REQ, tr("WAKEUP REQUEST")},
|
||||
{WaitState::SEMA, tr("SEMAPHORE")},
|
||||
{WaitState::SLEEP, tr("SLEEP")},
|
||||
{WaitState::DELAY, tr("DELAY")},
|
||||
{WaitState::EVENTFLAG, tr("EVENTFLAG")},
|
||||
{WaitState::MBOX, tr("MBOX")},
|
||||
{WaitState::VPOOL, tr("VPOOL")},
|
||||
{WaitState::FIXPOOL, tr("FIXPOOL")},
|
||||
};
|
||||
|
||||
DebugInterface& m_cpu;
|
||||
};
|
||||
|
||||
@@ -156,7 +156,7 @@ void DisplayWidget::handleCloseEvent(QCloseEvent* event)
|
||||
}
|
||||
else
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Q_ARG(bool, true));
|
||||
}
|
||||
|
||||
// Cancel the event from closing the window.
|
||||
|
||||
@@ -488,7 +488,7 @@ void GameListWidget::resizeTableViewColumnsToFit()
|
||||
80, // last played
|
||||
80, // size
|
||||
60, // region
|
||||
100 // compatibility
|
||||
120 // compatibility
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+61
-70
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -157,7 +157,7 @@ void MainWindow::initialize()
|
||||
restoreStateFromConfig();
|
||||
switchToGameListView();
|
||||
updateWindowTitle();
|
||||
updateSaveStateMenus(QString(), QString(), 0);
|
||||
updateSaveStateMenusEnableState(false);
|
||||
|
||||
#ifdef _WIN32
|
||||
registerForDeviceNotifications();
|
||||
@@ -346,7 +346,7 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.actionDiscordServer, &QAction::triggered, this, &MainWindow::onDiscordServerActionTriggered);
|
||||
connect(m_ui.actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
|
||||
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
|
||||
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
|
||||
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, [this]() { checkForUpdates(true, true); });
|
||||
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
||||
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
|
||||
@@ -963,10 +963,10 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
|
||||
}
|
||||
|
||||
const QString container(QString::fromStdString(
|
||||
Host::GetStringSettingValue("EmuCore/GS", "VideoCaptureContainer", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_CONTAINER)));
|
||||
Host::GetStringSettingValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER)));
|
||||
const QString filter(tr("%1 Files (*.%2)").arg(container.toUpper()).arg(container));
|
||||
|
||||
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseSnapshotFilename())).arg(container));
|
||||
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
|
||||
path = QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter);
|
||||
if (path.isEmpty())
|
||||
{
|
||||
@@ -1259,11 +1259,6 @@ void MainWindow::cancelGameListRefresh()
|
||||
m_game_list_widget->cancelRefresh();
|
||||
}
|
||||
|
||||
void MainWindow::invalidateSaveStateCache()
|
||||
{
|
||||
m_save_states_invalidated = true;
|
||||
}
|
||||
|
||||
void MainWindow::reportError(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::critical(this, title, message);
|
||||
@@ -1280,8 +1275,7 @@ void MainWindow::runOnUIThread(const std::function<void()>& func)
|
||||
func();
|
||||
}
|
||||
|
||||
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */,
|
||||
bool default_save_to_state /* = true */, bool block_until_done /* = false */)
|
||||
bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, bool default_save_to_state)
|
||||
{
|
||||
if (!s_vm_valid)
|
||||
return true;
|
||||
@@ -1326,34 +1320,21 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
||||
|
||||
// Now we can actually shut down the VM.
|
||||
g_emu_thread->shutdownVM(save_state);
|
||||
|
||||
if (block_until_done || m_is_closing || QtHost::InBatchMode())
|
||||
{
|
||||
// We need to yield here, since the display gets destroyed.
|
||||
while (VMManager::GetState() != VMState::Shutdown)
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
}
|
||||
|
||||
if (!m_is_closing && QtHost::InBatchMode())
|
||||
{
|
||||
// If we don't set the closing flag here, the VM shutdown may not complete by the time closeEvent() is called,
|
||||
// leading to a confirm.
|
||||
m_is_closing = true;
|
||||
QGuiApplication::quit();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::requestExit()
|
||||
void MainWindow::requestExit(bool allow_confirm)
|
||||
{
|
||||
// this is block, because otherwise closeEvent() will also prompt
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||
if (!requestShutdown(allow_confirm, true, EmuConfig.SaveStateOnShutdown))
|
||||
return;
|
||||
|
||||
// We could use close here, but if we're not visible (e.g. quitting from fullscreen), closing the window
|
||||
// doesn't quit the application.
|
||||
QGuiApplication::quit();
|
||||
// VM stopped signal won't have fired yet, so queue an exit if we still have one.
|
||||
// Otherwise, immediately exit, because there's no VM to exit us later.
|
||||
if (QtHost::IsVMValid())
|
||||
m_is_closing = true;
|
||||
else
|
||||
QGuiApplication::quit();
|
||||
}
|
||||
|
||||
void MainWindow::checkForSettingChanges()
|
||||
@@ -1374,11 +1355,6 @@ std::optional<WindowInfo> MainWindow::getWindowInfo()
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MainWindow::onGameListRefreshProgress(const QString& status, int current, int total)
|
||||
{
|
||||
m_ui.statusBar->showMessage(status);
|
||||
@@ -1387,6 +1363,7 @@ void MainWindow::onGameListRefreshProgress(const QString& status, int current, i
|
||||
|
||||
void MainWindow::onGameListRefreshComplete()
|
||||
{
|
||||
m_ui.statusBar->clearMessage();
|
||||
clearProgressBar();
|
||||
}
|
||||
|
||||
@@ -1487,7 +1464,6 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
|
||||
if (m_ui.menuDebug->menuAction()->isVisible())
|
||||
{
|
||||
// TODO: Hook this up once it's implemented.
|
||||
action = menu.addAction(tr("Boot and Debug"));
|
||||
connect(action, &QAction::triggered, [this, entry]() { DebugInterface::setPauseOnEntry(true); startGameListEntry(entry); getDebuggerWindow()->show(); });
|
||||
}
|
||||
@@ -1581,14 +1557,16 @@ void MainWindow::onChangeDiscMenuAboutToHide()
|
||||
|
||||
void MainWindow::onLoadStateMenuAboutToShow()
|
||||
{
|
||||
if (m_save_states_invalidated)
|
||||
updateSaveStateMenus(m_current_disc_path, m_current_game_serial, m_current_game_crc);
|
||||
m_ui.menuLoadState->clear();
|
||||
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
|
||||
populateLoadStateMenu(m_ui.menuLoadState, m_current_disc_path, m_current_game_serial, m_current_game_crc);
|
||||
}
|
||||
|
||||
void MainWindow::onSaveStateMenuAboutToShow()
|
||||
{
|
||||
if (m_save_states_invalidated)
|
||||
updateSaveStateMenus(m_current_disc_path, m_current_game_serial, m_current_game_crc);
|
||||
m_ui.menuSaveState->clear();
|
||||
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
|
||||
populateSaveStateMenu(m_ui.menuSaveState, m_current_game_serial, m_current_game_crc);
|
||||
}
|
||||
|
||||
void MainWindow::onViewToolbarActionToggled(bool checked)
|
||||
@@ -1676,15 +1654,7 @@ void MainWindow::onAboutActionTriggered()
|
||||
about.exec();
|
||||
}
|
||||
|
||||
void MainWindow::onCheckForUpdatesActionTriggered()
|
||||
{
|
||||
// Wipe out the last version, that way it displays the update if we've previously skipped it.
|
||||
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
|
||||
Host::CommitBaseSettingChanges();
|
||||
checkForUpdates(true);
|
||||
}
|
||||
|
||||
void MainWindow::checkForUpdates(bool display_message)
|
||||
void MainWindow::checkForUpdates(bool display_message, bool force_check)
|
||||
{
|
||||
if (!AutoUpdaterDialog::isSupported())
|
||||
{
|
||||
@@ -1715,6 +1685,13 @@ void MainWindow::checkForUpdates(bool display_message)
|
||||
if (m_auto_updater_dialog)
|
||||
return;
|
||||
|
||||
if (force_check)
|
||||
{
|
||||
// Wipe out the last version, that way it displays the update if we've previously skipped it.
|
||||
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
m_auto_updater_dialog = new AutoUpdaterDialog(this);
|
||||
connect(m_auto_updater_dialog, &AutoUpdaterDialog::updateCheckCompleted, this, &MainWindow::onUpdateCheckComplete);
|
||||
m_auto_updater_dialog->queueUpdateCheck(display_message);
|
||||
@@ -1734,7 +1711,7 @@ void MainWindow::startupUpdateCheck()
|
||||
if (!Host::GetBaseBoolSettingValue("AutoUpdater", "CheckAtStartup", true))
|
||||
return;
|
||||
|
||||
checkForUpdates(false);
|
||||
checkForUpdates(false, false);
|
||||
}
|
||||
|
||||
void MainWindow::onToolsOpenDataDirectoryTriggered()
|
||||
@@ -1890,7 +1867,7 @@ void MainWindow::onVMStarting()
|
||||
updateWindowTitle();
|
||||
|
||||
// prevent loading state until we're fully initialized
|
||||
updateSaveStateMenus(QString(), QString(), 0);
|
||||
updateSaveStateMenusEnableState(false);
|
||||
}
|
||||
|
||||
void MainWindow::onVMStarted()
|
||||
@@ -1952,6 +1929,14 @@ void MainWindow::onVMStopped()
|
||||
updateStatusBarWidgetVisibility();
|
||||
updateInputRecordingActions(false);
|
||||
|
||||
// If we're closing or in batch mode, quit the whole application now.
|
||||
if (m_is_closing || QtHost::InBatchMode())
|
||||
{
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
QCoreApplication::quit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_display_widget)
|
||||
updateDisplayWidgetCursor();
|
||||
else
|
||||
@@ -1970,7 +1955,7 @@ void MainWindow::onGameChanged(const QString& path, const QString& elf_override,
|
||||
m_current_game_name = name;
|
||||
m_current_game_crc = crc;
|
||||
updateWindowTitle();
|
||||
updateSaveStateMenus(path, serial, crc);
|
||||
updateSaveStateMenusEnableState(!serial.isEmpty());
|
||||
}
|
||||
|
||||
void MainWindow::showEvent(QShowEvent* event)
|
||||
@@ -1991,16 +1976,24 @@ void MainWindow::showEvent(QShowEvent* event)
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||
// If there's no VM, we can just exit as normal.
|
||||
if (!s_vm_valid)
|
||||
{
|
||||
event->ignore();
|
||||
QMainWindow::closeEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
// But if there is, we have to cancel the action, regardless of whether we ended exiting
|
||||
// or not. The window still needs to be visible while GS is shutting down.
|
||||
event->ignore();
|
||||
|
||||
// Exit cancelled?
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown))
|
||||
return;
|
||||
|
||||
// Application will be exited in VM stopped handler.
|
||||
saveStateToConfig();
|
||||
m_is_closing = true;
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
static QString getFilenameFromMimeData(const QMimeData* md)
|
||||
@@ -2265,7 +2258,12 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main, bool
|
||||
// Don't risk doing this on Wayland, it really doesn't like window state changes,
|
||||
// and positioning has no effect anyway.
|
||||
if (!s_use_central_widget)
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
{
|
||||
if (isVisible() && g_emu_thread->shouldRenderToMain())
|
||||
container->move(pos());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
}
|
||||
|
||||
if (!is_exclusive_fullscreen)
|
||||
container->showFullScreen();
|
||||
@@ -2826,21 +2824,14 @@ void MainWindow::populateSaveStateMenu(QMenu* menu, const QString& serial, quint
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc)
|
||||
void MainWindow::updateSaveStateMenusEnableState(bool enable)
|
||||
{
|
||||
const bool load_enabled = !serial.isEmpty();
|
||||
const bool save_enabled = !serial.isEmpty() && s_vm_valid;
|
||||
m_ui.menuLoadState->clear();
|
||||
const bool load_enabled = enable;
|
||||
const bool save_enabled = enable && s_vm_valid;
|
||||
m_ui.menuLoadState->setEnabled(load_enabled);
|
||||
m_ui.actionLoadState->setEnabled(load_enabled);
|
||||
m_ui.menuSaveState->clear();
|
||||
m_ui.menuSaveState->setEnabled(save_enabled);
|
||||
m_ui.actionSaveState->setEnabled(save_enabled);
|
||||
m_save_states_invalidated = false;
|
||||
if (load_enabled)
|
||||
populateLoadStateMenu(m_ui.menuLoadState, filename, serial, crc);
|
||||
if (save_enabled)
|
||||
populateSaveStateMenu(m_ui.menuSaveState, serial, crc);
|
||||
}
|
||||
|
||||
void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QString& path)
|
||||
|
||||
@@ -110,17 +110,17 @@ public:
|
||||
/// Rescans a single file. NOTE: Happens on UI thread.
|
||||
void rescanFile(const std::string& path);
|
||||
|
||||
void openDebugger();
|
||||
|
||||
public Q_SLOTS:
|
||||
void checkForUpdates(bool display_message);
|
||||
void checkForUpdates(bool display_message, bool force_check);
|
||||
void refreshGameList(bool invalidate_cache);
|
||||
void cancelGameListRefresh();
|
||||
void invalidateSaveStateCache();
|
||||
void reportError(const QString& title, const QString& message);
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
void runOnUIThread(const std::function<void()>& func);
|
||||
bool requestShutdown(
|
||||
bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true, bool block_until_done = false);
|
||||
void requestExit();
|
||||
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true);
|
||||
void requestExit(bool allow_confirm = true);
|
||||
void checkForSettingChanges();
|
||||
std::optional<WindowInfo> getWindowInfo();
|
||||
|
||||
@@ -162,7 +162,6 @@ private Q_SLOTS:
|
||||
void onSupportForumsActionTriggered();
|
||||
void onDiscordServerActionTriggered();
|
||||
void onAboutActionTriggered();
|
||||
void onCheckForUpdatesActionTriggered();
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
void onToolsCoverDownloaderTriggered();
|
||||
void updateTheme();
|
||||
@@ -244,7 +243,6 @@ private:
|
||||
void updateInputRecordingActions(bool started);
|
||||
|
||||
DebuggerWindow* getDebuggerWindow();
|
||||
void openDebugger();
|
||||
|
||||
ControllerSettingsDialog* getControllerSettingsDialog();
|
||||
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
|
||||
@@ -261,7 +259,7 @@ private:
|
||||
void loadSaveStateFile(const QString& filename, const QString& state_filename);
|
||||
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
|
||||
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
|
||||
void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc);
|
||||
void updateSaveStateMenusEnableState(bool enable);
|
||||
void doStartFile(std::optional<CDVD_SourceType> source, const QString& path);
|
||||
void doDiscChange(CDVD_SourceType source, const QString& path);
|
||||
|
||||
@@ -293,7 +291,6 @@ private:
|
||||
|
||||
bool m_display_created = false;
|
||||
bool m_relative_mouse_mode = false;
|
||||
bool m_save_states_invalidated = false;
|
||||
bool m_was_paused_on_surface_loss = false;
|
||||
bool m_was_disc_change_request = false;
|
||||
bool m_is_closing = false;
|
||||
|
||||
+43
-9
@@ -96,6 +96,7 @@ static bool s_nogui_mode = false;
|
||||
static bool s_start_fullscreen_ui = false;
|
||||
static bool s_start_fullscreen_ui_fullscreen = false;
|
||||
static bool s_test_config_and_exit = false;
|
||||
static bool s_boot_and_debug = false;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CPU Thread
|
||||
@@ -429,6 +430,10 @@ void EmuThread::executeVM()
|
||||
VMManager::Execute();
|
||||
continue;
|
||||
|
||||
case VMState::Resetting:
|
||||
VMManager::Reset();
|
||||
continue;
|
||||
|
||||
case VMState::Stopping:
|
||||
destroyVM();
|
||||
m_event_loop->processEvents(QEventLoop::AllEvents);
|
||||
@@ -861,6 +866,10 @@ void EmuThread::beginCapture(const QString& path)
|
||||
GetMTGS().RunOnGSThread([path = path.toStdString()]() {
|
||||
GSBeginCapture(std::move(path));
|
||||
});
|
||||
|
||||
// Sync GS thread. We want to start adding audio at the same time as video.
|
||||
// TODO: This could be up to 64 frames behind... use the pts to adjust it.
|
||||
GetMTGS().WaitGS(false, false, false);
|
||||
}
|
||||
|
||||
void EmuThread::endCapture()
|
||||
@@ -1220,12 +1229,9 @@ void Host::CancelGameListRefresh()
|
||||
QMetaObject::invokeMethod(g_main_window, "cancelGameListRefresh", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void Host::RequestExit(bool save_state_if_running)
|
||||
void Host::RequestExit(bool allow_confirm)
|
||||
{
|
||||
if (VMManager::HasValidVM())
|
||||
g_emu_thread->shutdownVM(save_state_if_running);
|
||||
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, allow_confirm));
|
||||
}
|
||||
|
||||
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state)
|
||||
@@ -1233,9 +1239,25 @@ void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool def
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
|
||||
Q_ARG(bool, allow_save_state), Q_ARG(bool, default_save_state), Q_ARG(bool, false));
|
||||
// This is a bit messy here - we want to shut down immediately (in case it was requested by the game),
|
||||
// but we also need to exit-on-shutdown for batch mode. So, if we're running on the CPU thread, destroy
|
||||
// the VM, then request the main window to exit.
|
||||
if (allow_confirm || !g_emu_thread->isOnEmuThread())
|
||||
{
|
||||
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
|
||||
Q_ARG(bool, allow_save_state), Q_ARG(bool, default_save_state));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change state to stopping -> return -> shut down VM.
|
||||
g_emu_thread->shutdownVM(allow_save_state && default_save_state);
|
||||
|
||||
// This will probably call shutdownVM() again, but by the time it runs, we'll have already shut down
|
||||
// and it'll be a noop.
|
||||
if (QtHost::InBatchMode())
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, false));
|
||||
}
|
||||
}
|
||||
|
||||
bool Host::IsFullscreen()
|
||||
@@ -1543,7 +1565,7 @@ static void SignalHandler(int signal)
|
||||
graceful_shutdown_attempted = true;
|
||||
|
||||
// This could be a bit risky invoking from a signal handler... hopefully it's okay.
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, false));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1600,6 +1622,7 @@ void QtHost::PrintCommandLineHelp(const std::string_view& progname)
|
||||
std::fprintf(stderr, " -nofullscreen: Prevents fullscreen mode from triggering if enabled.\n");
|
||||
std::fprintf(stderr, " -earlyconsolelog: Forces logging of early console messages to console.\n");
|
||||
std::fprintf(stderr, " -testconfig: Initializes configuration and checks version, then exits.\n");
|
||||
std::fprintf(stderr, " -debugger: Open debugger and break on entry point.\n");
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
std::fprintf(stderr, " -raintegration: Use RAIntegration instead of built-in achievement support.\n");
|
||||
#endif
|
||||
@@ -1722,6 +1745,11 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
|
||||
s_test_config_and_exit = true;
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG(QStringLiteral("-debugger")))
|
||||
{
|
||||
s_boot_and_debug = true;
|
||||
continue;
|
||||
}
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
else if (CHECK_ARG(QStringLiteral("-raintegration")))
|
||||
{
|
||||
@@ -1859,6 +1887,12 @@ int main(int argc, char* argv[])
|
||||
if (s_start_fullscreen_ui)
|
||||
g_emu_thread->startFullscreenUI(s_start_fullscreen_ui_fullscreen);
|
||||
|
||||
if (s_boot_and_debug)
|
||||
{
|
||||
DebugInterface::setPauseOnEntry(true);
|
||||
main_window->openDebugger();
|
||||
}
|
||||
|
||||
// Skip the update check if we're booting a game directly.
|
||||
if (autoboot)
|
||||
g_emu_thread->startVM(std::move(autoboot));
|
||||
|
||||
@@ -595,7 +595,7 @@ namespace SettingWidgetBinder
|
||||
/// Binds a widget's value to a setting, updating it when the value changes.
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToBoolSetting(
|
||||
static inline void BindWidgetToBoolSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -636,7 +636,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToIntSetting(
|
||||
static inline void BindWidgetToIntSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, int default_value, int option_offset = 0)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -677,7 +677,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToFloatSetting(
|
||||
static inline void BindWidgetToFloatSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -718,7 +718,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToNormalizedSetting(
|
||||
static inline void BindWidgetToNormalizedSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -759,7 +759,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToStringSetting(
|
||||
static inline void BindWidgetToStringSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -804,7 +804,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType, typename DataType>
|
||||
static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
std::optional<DataType> (*from_string_function)(const char* str), const char* (*to_string_function)(DataType value),
|
||||
DataType default_value)
|
||||
{
|
||||
@@ -866,7 +866,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType, typename DataType>
|
||||
static void BindWidgetToEnumSetting(
|
||||
static inline void BindWidgetToEnumSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, const char** enum_names, DataType default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -928,7 +928,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
const char** enum_names, const char** enum_values, const char* default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -992,7 +992,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
|
||||
static inline void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
|
||||
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value,
|
||||
bool use_relative = true)
|
||||
{
|
||||
@@ -1068,7 +1068,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
|
||||
static inline void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
|
||||
std::string section, std::string key, s32 default_value)
|
||||
{
|
||||
const s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
@@ -1109,8 +1109,8 @@ namespace SettingWidgetBinder
|
||||
});
|
||||
|
||||
slider->connect(slider, &QSlider::valueChanged, slider,
|
||||
[sif, label, label_suffix, section = std::move(section), key = std::move(key),
|
||||
orig_font = std::move(orig_font), bold_font = std::move(bold_font)](int value) {
|
||||
[sif, label, label_suffix, section = std::move(section), key = std::move(key), orig_font = std::move(orig_font),
|
||||
bold_font = std::move(bold_font)](int value) {
|
||||
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
|
||||
|
||||
if (label->font() != bold_font)
|
||||
|
||||
@@ -105,14 +105,13 @@ void AchievementSettingsWidget::updateEnableState()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("Achievements", "Enabled", false);
|
||||
const bool challenge = m_dialog->getEffectiveBoolValue("Achievements", "ChallengeMode", false);
|
||||
const bool notifications = m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true);
|
||||
m_ui.testMode->setEnabled(enabled);
|
||||
m_ui.unofficialTestMode->setEnabled(enabled);
|
||||
m_ui.richPresence->setEnabled(enabled);
|
||||
m_ui.challengeMode->setEnabled(enabled);
|
||||
m_ui.leaderboards->setEnabled(enabled && challenge);
|
||||
m_ui.notifications->setEnabled(enabled);
|
||||
m_ui.soundEffects->setEnabled(enabled && notifications);
|
||||
m_ui.soundEffects->setEnabled(enabled);
|
||||
m_ui.primedIndicators->setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeINTCSpinDetection, "EmuCore/Speedhacks", "IntcStat", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeWaitLoopDetection, "EmuCore/Speedhacks", "WaitLoop", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeFastmem, "EmuCore/CPU/Recompiler", "EnableFastmem", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnTLBMiss, "EmuCore/CPU/Recompiler", "PauseOnTLBMiss", false);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu0Recompiler, "EmuCore/CPU/Recompiler", "EnableVU0", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu1Recompiler, "EmuCore/CPU/Recompiler", "EnableVU1", true);
|
||||
@@ -84,6 +85,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.eeFastmem, tr("Enable Fast Memory Access"), tr("Checked"),
|
||||
tr("Uses backpatching to avoid register flushing on every memory access."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnTLBMiss, tr("Pause On TLB Miss"), tr("Unchecked"),
|
||||
tr("Pauses the virtual machine when a TLB miss occurs, instead of ignoring it and continuing. Note the the VM will pause after the "
|
||||
"end of the block, not on the instruction which caused the exception. Refer to the console to see the address where the invalid "
|
||||
"access occurred."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.vu0RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu1RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
|
||||
|
||||
@@ -165,6 +165,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="pauseOnTLBMiss">
|
||||
<property name="text">
|
||||
<string>Pause On TLB Miss</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -42,10 +42,12 @@
|
||||
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
, m_config_section(StringUtil::StdStringFromFormat("Pad%u", port + 1u))
|
||||
, m_config_section(fmt::format("Pad{}", port + 1))
|
||||
, m_port_number(port)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.groupBox->setTitle(tr("Controller Port %1").arg(port + 1));
|
||||
|
||||
populateControllerTypes();
|
||||
onTypeChanged();
|
||||
|
||||
@@ -113,10 +115,9 @@ void ControllerBindingWidget::onTypeChanged()
|
||||
|
||||
if (has_settings)
|
||||
{
|
||||
const QString settings_title(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name)));
|
||||
const gsl::span<const SettingInfo> settings(cinfo->settings, cinfo->num_settings);
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, std::string(), settings_title, cinfo->name, getDialog(), m_ui.stackedWidget);
|
||||
m_settings_widget =
|
||||
new ControllerCustomSettingsWidget(settings, m_config_section, std::string(), cinfo->name, getDialog(), m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
@@ -458,8 +459,7 @@ void ControllerMacroEditWidget::updateBinds()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section,
|
||||
std::string config_prefix, const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog,
|
||||
QWidget* parent_widget)
|
||||
std::string config_prefix, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget)
|
||||
: QWidget(parent_widget)
|
||||
, m_settings(settings)
|
||||
, m_config_section(std::move(config_section))
|
||||
@@ -469,22 +469,19 @@ ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const S
|
||||
if (settings.empty())
|
||||
return;
|
||||
|
||||
QGroupBox* gbox = new QGroupBox(group_title, this);
|
||||
QGridLayout* gbox_layout = new QGridLayout(gbox);
|
||||
createSettingWidgets(translation_ctx, gbox, gbox_layout);
|
||||
QScrollArea* sarea = new QScrollArea(this);
|
||||
QWidget* swidget = new QWidget(sarea);
|
||||
sarea->setWidget(swidget);
|
||||
sarea->setWidgetResizable(true);
|
||||
sarea->setFrameShape(QFrame::StyledPanel);
|
||||
sarea->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
QGridLayout* swidget_layout = new QGridLayout(swidget);
|
||||
createSettingWidgets(translation_ctx, swidget, swidget_layout);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(gbox);
|
||||
|
||||
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
|
||||
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
|
||||
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
|
||||
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
|
||||
bottom_hlayout->addStretch(1);
|
||||
bottom_hlayout->addWidget(restore_defaults);
|
||||
layout->addLayout(bottom_hlayout);
|
||||
layout->addStretch(1);
|
||||
layout->addWidget(sarea);
|
||||
}
|
||||
|
||||
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() = default;
|
||||
@@ -503,8 +500,6 @@ static std::tuple<QString, QString> getPrefixAndSuffixForIntFormat(const QString
|
||||
return std::tie(prefix, suffix);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Unused until we handle multiplier below.
|
||||
static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const QString& format)
|
||||
{
|
||||
QString prefix, suffix;
|
||||
@@ -532,7 +527,6 @@ static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const
|
||||
|
||||
return std::tie(prefix, suffix, decimals);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ControllerCustomSettingsWidget::createSettingWidgets(const char* translation_ctx, QWidget* widget_parent, QGridLayout* layout)
|
||||
{
|
||||
@@ -569,7 +563,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
sb->setPrefix(prefix);
|
||||
sb->setSuffix(suffix);
|
||||
}
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
|
||||
sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(sb, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -582,7 +577,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
cb->setObjectName(QString::fromUtf8(si.name));
|
||||
for (u32 i = 0; si.options[i] != nullptr; i++)
|
||||
cb->addItem(qApp->translate(translation_ctx, si.options[i]));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
|
||||
sif, cb, m_config_section, std::move(key_name), si.IntegerDefaultValue(), si.IntegerMinValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(cb, current_row, 1, 1, 3);
|
||||
@@ -594,11 +589,10 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
{
|
||||
QDoubleSpinBox* sb = new QDoubleSpinBox(widget_parent);
|
||||
sb->setObjectName(QString::fromUtf8(si.name));
|
||||
sb->setMinimum(si.FloatMinValue());
|
||||
sb->setMaximum(si.FloatMaxValue());
|
||||
sb->setSingleStep(si.FloatStepValue());
|
||||
#if 0
|
||||
// We can't use this until we handle multiplier.
|
||||
sb->setMinimum(si.FloatMinValue() * si.multiplier);
|
||||
sb->setMaximum(si.FloatMaxValue() * si.multiplier);
|
||||
sb->setSingleStep(si.FloatStepValue() * si.multiplier);
|
||||
|
||||
if (si.format)
|
||||
{
|
||||
const auto [prefix, suffix, decimals] = getPrefixAndSuffixForFloatFormat(QString::fromUtf8(si.format));
|
||||
@@ -607,8 +601,9 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
sb->setDecimals(decimals);
|
||||
sb->setSuffix(suffix);
|
||||
}
|
||||
#endif
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue());
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(
|
||||
sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue(), si.multiplier);
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(sb, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -619,7 +614,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
{
|
||||
QLineEdit* le = new QLineEdit(widget_parent);
|
||||
le->setObjectName(QString::fromUtf8(si.name));
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(le, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -641,7 +637,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
for (u32 i = 0; si.options[i] != nullptr; i++)
|
||||
cb->addItem(qApp->translate(translation_ctx, si.options[i]), QString::fromUtf8(si.options[i]));
|
||||
}
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(cb, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -653,7 +650,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
QLineEdit* le = new QLineEdit(widget_parent);
|
||||
le->setObjectName(QString::fromUtf8(si.name));
|
||||
QPushButton* browse_button = new QPushButton(tr("Browse..."), widget_parent);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
connect(browse_button, &QPushButton::clicked, [this, le]() {
|
||||
const QString path(QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select File"))));
|
||||
if (!path.isEmpty())
|
||||
@@ -677,6 +675,16 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
|
||||
layout->addItem(new QSpacerItem(1, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), current_row++, 0, 1, 4);
|
||||
}
|
||||
|
||||
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
|
||||
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
|
||||
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
|
||||
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
|
||||
bottom_hlayout->addStretch(1);
|
||||
bottom_hlayout->addWidget(restore_defaults);
|
||||
layout->addLayout(bottom_hlayout, current_row++, 0, 1, 4);
|
||||
|
||||
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), current_row++, 0, 1, 4);
|
||||
}
|
||||
|
||||
void ControllerCustomSettingsWidget::restoreDefaults()
|
||||
@@ -715,7 +723,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
|
||||
{
|
||||
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name));
|
||||
if (widget)
|
||||
widget->setValue(si.FloatDefaultValue());
|
||||
widget->setValue(si.FloatDefaultValue() * si.multiplier);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -851,10 +859,12 @@ ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance
|
||||
USBDeviceWidget::USBDeviceWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
, m_config_section(StringUtil::StdStringFromFormat("USB%u", port + 1u))
|
||||
, m_config_section(fmt::format("USB{}", port + 1))
|
||||
, m_port_number(port)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.groupBox->setTitle(tr("USB Port %1").arg(port + 1));
|
||||
|
||||
populateDeviceTypes();
|
||||
populatePages();
|
||||
|
||||
@@ -926,9 +936,8 @@ void USBDeviceWidget::populatePages()
|
||||
|
||||
if (!settings.empty())
|
||||
{
|
||||
const QString settings_title(tr("Device Settings"));
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, m_device_type + "_", settings_title, m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
|
||||
settings, m_config_section, m_device_type + "_", m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ class ControllerCustomSettingsWidget : public QWidget
|
||||
|
||||
public:
|
||||
ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section, std::string config_prefix,
|
||||
const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
|
||||
const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
|
||||
~ControllerCustomSettingsWidget();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
@@ -151,7 +151,7 @@ void ControllerLEDSettingsDialog::linkButton(ColorPickerButton* button, u32 play
|
||||
const u32 current_value = SDLInputSource::ParseRGBForPlayerId(m_dialog->getStringValue("SDLExtra", key.c_str(), ""), player_id);
|
||||
button->setColor(current_value);
|
||||
|
||||
connect(button, &ColorPickerButton::colorChanged, this, [this, player_id, key = std::move(key)](u32 new_rgb) {
|
||||
connect(button, &ColorPickerButton::colorChanged, this, [this, key = std::move(key)](u32 new_rgb) {
|
||||
m_dialog->setStringValue("SDLExtra", key.c_str(), fmt::format("{:06X}", new_rgb).c_str());
|
||||
});
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace ControllerSettingWidgetBinder
|
||||
{
|
||||
/// Interface specific method of BindWidgetToBoolSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileBool(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
static inline void BindWidgetToInputProfileBool(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
@@ -68,19 +69,53 @@ namespace ControllerSettingWidgetBinder
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToIntSetting().
|
||||
template <typename WidgetType>
|
||||
static inline void BindWidgetToInputProfileInt(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, s32 default_value, s32 option_offset = 0)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const s32 value = sif->GetIntValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setIntValue(widget, value - option_offset);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), option_offset]() {
|
||||
const float new_value = Accessor::getIntValue(widget);
|
||||
sif->SetIntValue(section.c_str(), key.c_str(), new_value + option_offset);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
const s32 value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setIntValue(widget, value - option_offset);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), option_offset]() {
|
||||
const s32 new_value = Accessor::getIntValue(widget);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToFloatSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileFloat(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
||||
static inline void BindWidgetToInputProfileFloat(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value, float multiplier = 1.0f)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setFloatValue(widget, value);
|
||||
Accessor::setFloatValue(widget, value * multiplier);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
|
||||
const float new_value = Accessor::getFloatValue(widget);
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), multiplier]() {
|
||||
const float new_value = Accessor::getFloatValue(widget) / multiplier;
|
||||
sif->SetFloatValue(section.c_str(), key.c_str(), new_value);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
@@ -89,10 +124,10 @@ namespace ControllerSettingWidgetBinder
|
||||
else
|
||||
{
|
||||
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setFloatValue(widget, value);
|
||||
Accessor::setFloatValue(widget, value * multiplier);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
||||
const float new_value = Accessor::getFloatValue(widget);
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), multiplier]() {
|
||||
const float new_value = Accessor::getFloatValue(widget) / multiplier;
|
||||
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_emu_thread->applySettings();
|
||||
@@ -102,12 +137,11 @@ namespace ControllerSettingWidgetBinder
|
||||
|
||||
/// Interface specific method of BindWidgetToNormalizedSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileNormalized(
|
||||
static inline void BindWidgetToInputProfileNormalized(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
|
||||
@@ -136,7 +170,7 @@ namespace ControllerSettingWidgetBinder
|
||||
|
||||
/// Interface specific method of BindWidgetToStringSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileString(
|
||||
static inline void BindWidgetToInputProfileString(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
@@ -160,7 +194,8 @@ namespace ControllerSettingWidgetBinder
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString value(QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
|
||||
const QString value(
|
||||
QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
|
||||
|
||||
Accessor::setStringValue(widget, value);
|
||||
|
||||
|
||||
@@ -260,9 +260,13 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hddEnabled, "DEV9/Hdd", "HddEnable", false);
|
||||
|
||||
connect(m_ui.hddFile, &QLineEdit::editingFinished, this, &DEV9SettingsWidget::onHddFileEdit);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.hddFile, "DEV9/Hdd", "HddFile", "DEV9hdd.raw");
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "").value().c_str()));
|
||||
m_ui.hddFile->setPlaceholderText(QString::fromUtf8(Host::GetBaseStringSettingValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw")));
|
||||
}
|
||||
else
|
||||
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw").value().c_str()));
|
||||
connect(m_ui.hddBrowseFile, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddBrowseFileClicked);
|
||||
|
||||
//TODO: need a getUintValue for if 48bit support occurs
|
||||
@@ -270,18 +274,27 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
std::optional<int> sizeOpt = std::nullopt;
|
||||
if (size > 0)
|
||||
sizeOpt = size;
|
||||
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
|
||||
m_ui.hddSizeSpinBox->setMinimum(39);
|
||||
m_ui.hddSizeSpinBox->setSpecialValueText(tr("Global [%1]").arg(sizeGlobal));
|
||||
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::makeNullableInt(m_ui.hddSizeSpinBox, sizeGlobal);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, sizeOpt);
|
||||
|
||||
m_ui.hddSizeSlider->setValue(sizeOpt.value_or(sizeGlobal));
|
||||
|
||||
m_ui.hddSizeSlider->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.hddSizeSlider, &QSlider::customContextMenuRequested, this, &DEV9SettingsWidget::onHddSizeSliderContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.hddSizeSlider->setValue(size);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setIntValue(m_ui.hddSizeSpinBox, size);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
m_ui.hddSizeSlider ->setValue(size);
|
||||
m_ui.hddSizeSpinBox->setValue(size);
|
||||
|
||||
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider ::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
|
||||
connect(m_ui.hddSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &DEV9SettingsWidget::onHddSizeSpin );
|
||||
// clang-format on
|
||||
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::connectValueChanged(m_ui.hddSizeSpinBox, [&]() { onHddSizeAccessorSpin(); });
|
||||
|
||||
connect(m_ui.hddCreate, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddCreateClicked);
|
||||
}
|
||||
@@ -682,7 +695,7 @@ void DEV9SettingsWidget::onEthHostEdit(QStandardItem* item)
|
||||
|
||||
void DEV9SettingsWidget::onHddEnabledChanged(int state)
|
||||
{
|
||||
const bool enabled = state == Qt::CheckState::PartiallyChecked ? m_dialog->getEffectiveBoolValue("DEV9/Hdd", "HddEnable", false) : state;
|
||||
const bool enabled = state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("DEV9/Hdd", "HddEnable", false) : state;
|
||||
|
||||
m_ui.hddFile->setEnabled(enabled);
|
||||
m_ui.hddFileLabel->setEnabled(enabled);
|
||||
@@ -699,8 +712,8 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
|
||||
{
|
||||
QString path =
|
||||
QDir::toNativeSeparators(QFileDialog::getSaveFileName(QtUtils::GetRootWidget(this), tr("HDD Image File"),
|
||||
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : "DEV9hdd.raw", tr("HDD (*.raw)"), nullptr,
|
||||
QFileDialog::DontConfirmOverwrite));
|
||||
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : (!m_ui.hddFile->placeholderText().isEmpty() ? m_ui.hddFile->placeholderText() : "DEV9hdd.raw"),
|
||||
tr("HDD (*.raw)"), nullptr, QFileDialog::DontConfirmOverwrite));
|
||||
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
@@ -711,10 +724,16 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
|
||||
|
||||
void DEV9SettingsWidget::onHddFileEdit()
|
||||
{
|
||||
//Check if file exists, if so set HddSize to correct value
|
||||
// Check if file exists, if so set HddSize to correct value.
|
||||
// Also save the hddPath setting
|
||||
std::string hddPath(m_ui.hddFile->text().toStdString());
|
||||
if (hddPath.empty())
|
||||
{
|
||||
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", std::nullopt);
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", hddPath.c_str());
|
||||
|
||||
if (!Path::IsAbsolute(hddPath))
|
||||
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
|
||||
@@ -739,22 +758,49 @@ void DEV9SettingsWidget::onHddFileEdit()
|
||||
|
||||
void DEV9SettingsWidget::onHddSizeSlide(int i)
|
||||
{
|
||||
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered null when the valueChanged signal is fired
|
||||
QSignalBlocker sb(m_ui.hddSizeSpinBox);
|
||||
m_ui.hddSizeSpinBox->setValue(i);
|
||||
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", (int)((s64)i * 1024 * 1024 * 1024 / 512));
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, i);
|
||||
onHddSizeAccessorSpin();
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddSizeSpin(int i)
|
||||
void DEV9SettingsWidget::onHddSizeSliderContext(const QPoint& pt)
|
||||
{
|
||||
QSignalBlocker sb(m_ui.hddSizeSlider);
|
||||
m_ui.hddSizeSlider->setValue(i);
|
||||
QMenu menu(m_ui.hddSizeSlider);
|
||||
connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, this, &DEV9SettingsWidget::onHddSizeSliderReset);
|
||||
menu.exec(m_ui.hddSizeSlider->mapToGlobal(pt));
|
||||
}
|
||||
|
||||
//TODO: need a setUintSettingValue for if 48bit support occurs
|
||||
if (i == 39)
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
|
||||
void DEV9SettingsWidget::onHddSizeSliderReset([[maybe_unused]] bool checked)
|
||||
{
|
||||
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered non-null when the valueChanged signal is fired
|
||||
QSignalBlocker sb(m_ui.hddSizeSpinBox);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, std::nullopt);
|
||||
onHddSizeAccessorSpin();
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddSizeAccessorSpin()
|
||||
{
|
||||
//TODO: need a getUintValue for if 48bit support occurs
|
||||
QSignalBlocker sb(m_ui.hddSizeSlider);
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
std::optional<int> new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getNullableIntValue(m_ui.hddSizeSpinBox);
|
||||
|
||||
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
|
||||
m_ui.hddSizeSlider->setValue(new_value.value_or(sizeGlobal));
|
||||
|
||||
if (new_value.has_value())
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value.value() * (1024 * 1024 * 1024 / 512));
|
||||
else
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
|
||||
}
|
||||
else
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", i * (1024 * 1024 * 1024 / 512));
|
||||
{
|
||||
const int new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getIntValue(m_ui.hddSizeSpinBox);
|
||||
m_ui.hddSizeSlider->setValue(new_value);
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value * (1024 * 1024 * 1024 / 512));
|
||||
}
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddCreateClicked()
|
||||
@@ -774,7 +820,7 @@ void DEV9SettingsWidget::onHddCreateClicked()
|
||||
if (!Path::IsAbsolute(hddPath))
|
||||
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
|
||||
|
||||
if (!FileSystem::FileExists(hddPath.c_str()))
|
||||
if (FileSystem::FileExists(hddPath.c_str()))
|
||||
{
|
||||
//GHC uses UTF8 on all platforms
|
||||
QMessageBox::StandardButton selection =
|
||||
|
||||
@@ -49,7 +49,11 @@ private Q_SLOTS:
|
||||
void onHddBrowseFileClicked();
|
||||
void onHddFileEdit();
|
||||
void onHddSizeSlide(int i);
|
||||
void onHddSizeSpin(int i);
|
||||
// Per game only.
|
||||
void onHddSizeSliderContext(const QPoint& pt);
|
||||
void onHddSizeSliderReset(bool checked = false);
|
||||
//
|
||||
void onHddSizeAccessorSpin();
|
||||
void onHddCreateClicked();
|
||||
|
||||
public:
|
||||
|
||||
@@ -346,6 +346,11 @@
|
||||
<string>In-Game</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Playable</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Perfect</string>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -97,7 +97,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.fmvAspectRatio, "EmuCore/GS", "FMVAspectRatioSwitch",
|
||||
Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, FMVAspectRatioSwitchType::Off);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.interlacing, "EmuCore/GS", "deinterlace_mode", DEFAULT_INTERLACE_MODE);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.noInterlacingPatches, "EmuCore", "EnableNoInterlacingPatches", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.integerScaling, "EmuCore/GS", "IntegerScaling", false);
|
||||
@@ -105,8 +106,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOverscan, "EmuCore/GS", "pcrtc_overscan", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCAntiBlur, "EmuCore/GS", "pcrtc_antiblur", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.DisableInterlaceOffset, "EmuCore/GS", "disable_interlace_offset", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotSize, "EmuCore/GS", "ScreenshotSize", static_cast<int>(GSScreenshotSize::WindowResolution));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.screenshotSize, "EmuCore/GS", "ScreenshotSize", static_cast<int>(GSScreenshotSize::WindowResolution));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "EmuCore/GS", "ScreenshotQuality", 50);
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropLeft, "EmuCore/GS", "CropLeft", 0);
|
||||
@@ -114,7 +117,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropRight, "EmuCore/GS", "CropRight", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropBottom, "EmuCore/GS", "CropBottom", 0);
|
||||
|
||||
connect(m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
|
||||
connect(
|
||||
m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// OSD Settings
|
||||
@@ -147,55 +151,33 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HW Settings
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static const char* upscale_entries[] = {
|
||||
"Native (PS2) (Default)",
|
||||
"1.25x Native",
|
||||
"1.5x Native",
|
||||
"1.75x Native",
|
||||
"2x Native (~720p)",
|
||||
"2.25x Native",
|
||||
"2.5x Native",
|
||||
"2.75x Native",
|
||||
"3x Native (~1080p)",
|
||||
"3.5x Native",
|
||||
"4x Native (~1440p/2K)",
|
||||
"5x Native (~1620p)",
|
||||
"6x Native (~2160p/4K)",
|
||||
"7x Native (~2520p)",
|
||||
"8x Native (~2880p/5K)",
|
||||
nullptr};
|
||||
static const char* upscale_entries[] = {"Native (PS2) (Default)", "1.25x Native", "1.5x Native", "1.75x Native", "2x Native (~720p)",
|
||||
"2.25x Native", "2.5x Native", "2.75x Native", "3x Native (~1080p)", "3.5x Native", "4x Native (~1440p/2K)", "5x Native (~1620p)",
|
||||
"6x Native (~2160p/4K)", "7x Native (~2520p)", "8x Native (~2880p/5K)", nullptr};
|
||||
static const char* upscale_values[] = {
|
||||
"1",
|
||||
"1.25",
|
||||
"1.5",
|
||||
"1.75",
|
||||
"2",
|
||||
"2.25",
|
||||
"2.5",
|
||||
"2.75",
|
||||
"3",
|
||||
"3.5",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
nullptr };
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
|
||||
"1", "1.25", "1.5", "1.75", "2", "2.25", "2.5", "2.75", "3", "3.5", "4", "5", "6", "7", "8", nullptr};
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(
|
||||
sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy", s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0");
|
||||
sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy",
|
||||
s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0");
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.dithering, "EmuCore/GS", "dithering_ps2", 2);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.mipmapping, "EmuCore/GS", "mipmap_hw", static_cast<int>(HWMipmapLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.mipmapping, "EmuCore/GS", "mipmap_hw", static_cast<int>(HWMipmapLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading",
|
||||
static_cast<int>(TexturePreloadingLevel::Off));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off));
|
||||
|
||||
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onTrilinearFilteringChanged);
|
||||
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this, &GraphicsSettingsWidget::onGpuPaletteConversionChanged);
|
||||
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onTrilinearFilteringChanged);
|
||||
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this,
|
||||
&GraphicsSettingsWidget::onGpuPaletteConversionChanged);
|
||||
onTrilinearFilteringChanged();
|
||||
onGpuPaletteConversionChanged(m_ui.gpuPaletteConversion->checkState());
|
||||
|
||||
@@ -213,7 +195,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDepthEmulation, "EmuCore/GS", "UserHacks_DisableDepthSupport", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableSafeFeatures, "EmuCore/GS", "UserHacks_Disable_Safe_Features", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preloadFrameData, "EmuCore/GS", "preload_frame_with_gs_data", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", false);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -234,7 +217,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpReplaceableMipmaps, "EmuCore/GS", "DumpReplaceableMipmaps", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpTexturesWithFMVActive, "EmuCore/GS", "DumpTexturesWithFMVActive", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacements, "EmuCore/GS", "LoadTextureReplacements", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.precacheTextureReplacements, "EmuCore/GS", "PrecacheTextureReplacements", false);
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.texturesDirectory, m_ui.texturesBrowse, m_ui.texturesOpen, m_ui.texturesReset,
|
||||
"Folders", "Textures", Path::Combine(EmuFolders::DataRoot, "textures"));
|
||||
@@ -248,10 +232,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.threadedPresentation, "EmuCore/GS", "DisableThreadedPresentation", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideTextureBarriers, "EmuCore/GS", "OverrideTextureBarriers", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideGeometryShader, "EmuCore/GS", "OverrideGeometryShaders", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "EmuCore/GS", "DisableFramebufferFetch", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDualSource, "EmuCore/GS", "DisableDualSourceBlend", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SW Settings
|
||||
@@ -315,19 +301,53 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
// Capture settings
|
||||
{
|
||||
for (const char** container = Pcsx2Config::GSOptions::VideoCaptureContainers; *container; container++)
|
||||
for (const char** container = Pcsx2Config::GSOptions::CaptureContainers; *container; container++)
|
||||
{
|
||||
const QString name(QString::fromUtf8(*container));
|
||||
m_ui.videoCaptureContainer->addItem(name.toUpper(), name);
|
||||
m_ui.captureContainer->addItem(name.toUpper(), name);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureContainer, "EmuCore/GS", "VideoCaptureContainer");
|
||||
connect(m_ui.videoCaptureContainer, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onVideoCaptureContainerChanged);
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse,
|
||||
m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset, "Folders", "Videos",
|
||||
Path::Combine(EmuFolders::DataRoot, "videos"));
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.captureContainer, "EmuCore/GS", "CaptureContainer");
|
||||
connect(m_ui.captureContainer, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureContainerChanged);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCapture, "EmuCore/GS", "EnableVideoCapture", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.videoCaptureBitrate, "EmuCore/GS", "VideoCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_BITRATE);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.videoCaptureWidth, "EmuCore/GS", "VideoCaptureWidth", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_WIDTH);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.videoCaptureHeight, "EmuCore/GS", "VideoCaptureHeight", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_HEIGHT);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.videoCaptureResolutionAuto, "EmuCore/GS", "VideoCaptureAutoResolution", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.enableVideoCaptureArguments, "EmuCore/GS", "EnableVideoCaptureParameters", false);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureArguments, "EmuCore/GS", "VideoCaptureParameters");
|
||||
connect(m_ui.enableVideoCapture, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableVideoCaptureChanged);
|
||||
connect(
|
||||
m_ui.videoCaptureResolutionAuto, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onVideoCaptureAutoResolutionChanged);
|
||||
connect(m_ui.enableVideoCaptureArguments, &QCheckBox::stateChanged, this,
|
||||
&GraphicsSettingsWidget::onEnableVideoCaptureArgumentsChanged);
|
||||
|
||||
onVideoCaptureContainerChanged();
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableAudioCapture, "EmuCore/GS", "EnableAudioCapture", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.audioCaptureBitrate, "EmuCore/GS", "AudioCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_AUDIO_CAPTURE_BITRATE);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.enableAudioCaptureArguments, "EmuCore/GS", "EnableAudioCaptureParameters", false);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureArguments, "EmuCore/GS", "AudioCaptureParameters");
|
||||
connect(m_ui.enableAudioCapture, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableAudioCaptureChanged);
|
||||
connect(m_ui.enableAudioCaptureArguments, &QCheckBox::stateChanged, this,
|
||||
&GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged);
|
||||
|
||||
onCaptureContainerChanged();
|
||||
onEnableVideoCaptureChanged();
|
||||
onEnableVideoCaptureArgumentsChanged();
|
||||
onVideoCaptureAutoResolutionChanged();
|
||||
onEnableAudioCaptureChanged();
|
||||
onEnableAudioCaptureArgumentsChanged();
|
||||
}
|
||||
|
||||
// Display tab
|
||||
@@ -342,39 +362,45 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Disables interlacing offset which may reduce blurring in some situations."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.bilinearFiltering, tr("Bilinear Filtering"), tr("Bilinear (Smooth)"),
|
||||
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects positioning between pixels."));
|
||||
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects "
|
||||
"positioning between pixels."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCOffsets, tr("Screen Offsets"), tr("Unchecked"),
|
||||
tr("Enables PCRTC Offsets which position the screen as the game requests. Useful for some games such as WipEout Fusion for its screen shake effect, but can make the picture blurry."));
|
||||
tr("Enables PCRTC Offsets which position the screen as the game requests. Useful for some games such as WipEout Fusion for its "
|
||||
"screen shake effect, but can make the picture blurry."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCOverscan, tr("Show Overscan"), tr("Unchecked"),
|
||||
tr("Enables the option to show the overscan area on games which draw more than the safe area of the screen."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"),
|
||||
tr("Overrides the FMV aspect ratio."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"), tr("Overrides the FMV aspect ratio."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCAntiBlur, tr("Anti-Blur"), tr("Checked"),
|
||||
tr("Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry."));
|
||||
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.vsync, tr("VSync"), tr("Unchecked"),
|
||||
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when it is not possible (eg. running at non-100% speed)."));
|
||||
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when "
|
||||
"it is not possible (eg. running at non-100% speed)."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.integerScaling, tr("Integer Scaling"), tr("Unchecked"),
|
||||
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer number. May result in a sharper image in some 2D games."));
|
||||
|
||||
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an "
|
||||
"integer number. May result in a sharper image in some 2D games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"),
|
||||
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto Standard (4:3/3:2 Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
|
||||
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto Standard (4:3/3:2 "
|
||||
"Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.screenshotSize, tr("Screenshot Size"), tr("Screen Resolution"),
|
||||
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of file size."));
|
||||
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of "
|
||||
"file size."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.screenshotFormat, tr("Screenshot Format"), tr("PNG"),
|
||||
tr("Selects the format which will be used to save screenshots. JPEG produces smaller files, but loses detail."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.screenshotQuality, tr("Screenshot Quality"), tr("50%"),
|
||||
tr("Selects the quality at which screenshots will be compressed. Higher values preserve more detail for JPEG, and reduce file size for PNG."));
|
||||
tr("Selects the quality at which screenshots will be compressed. Higher values preserve more detail for JPEG, and reduce file "
|
||||
"size for PNG."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.stretchY, tr("Stretch Height"), tr("100%"), tr(""));
|
||||
|
||||
@@ -395,11 +421,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
// Hardware
|
||||
dialog->registerWidgetHelp(m_ui.upscaleMultiplier, tr("Internal Resolution"), tr("Native (PS2) (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"),
|
||||
tr("Control the accuracy level of the mipmapping emulation."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"), tr("Control the accuracy level of the mipmapping emulation."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"),
|
||||
tr("Control the texture filtering of the emulation."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"), tr("Control the texture filtering of the emulation."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.trilinearFiltering, tr("Trilinear Filtering"), tr("Automatic (Default)"),
|
||||
tr("Control the texture tri-filtering of the emulation."));
|
||||
@@ -417,8 +443,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Control the number of Auto-CRC fixes and hacks applied to games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.blending, tr("Blending Accuracy"), tr("Basic (Recommended)"),
|
||||
tr("Control the accuracy level of the GS blending unit emulation. "
|
||||
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will be. "
|
||||
tr("Control the accuracy level of the GS blending unit emulation.<br> "
|
||||
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will "
|
||||
"be.<br> "
|
||||
"Do note that Direct3D's blending is reduced in capability compared to OpenGL/Vulkan"));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.texturePreloading, tr("Texture Preloading"), tr("Full (Hash Cache)"),
|
||||
@@ -445,15 +472,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
// Software
|
||||
dialog->registerWidgetHelp(m_ui.extraSWThreads, tr("Extra Rendering Threads"), tr("2 threads"),
|
||||
tr("Number of rendering threads: 0 for single thread, 2 or more for multithread (1 is for debugging). "
|
||||
"If you have 4 threads on your CPU pick 2 or 3. You can calculate how to get the best performance (amount of CPU threads - 2). "
|
||||
"If you have 4 threads on your CPU pick 2 or 3. You can calculate how to get the best performance (amount of CPU threads - "
|
||||
"2). "
|
||||
"7+ threads will not give much more performance and could perhaps even lower it."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.swAutoFlush, tr("Auto Flush"), tr("Checked"),
|
||||
tr("Force a primitive flush when a framebuffer is also an input texture. "
|
||||
"Fixes some processing effects such as the shadows in the Jak series and radiosity in GTA:SA."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.swMipmap, tr("Mipmapping"), tr("Checked"),
|
||||
tr("Enables mipmapping, which some games require to render correctly."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.swMipmap, tr("Mipmapping"), tr("Checked"), tr("Enables mipmapping, which some games require to render correctly."));
|
||||
}
|
||||
|
||||
// Hardware Fixes tab
|
||||
@@ -482,7 +510,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.disableSafeFeatures, tr("Disable Safe Features"), tr("Unchecked"),
|
||||
tr("This option disables multiple safe features. "
|
||||
"Disables accurate Unscale Point and Line rendering which can help Xenosaga games. "
|
||||
"Disables accurate GS Memory Clearing to be done on the CPU, and let the GPU handle it, which can help Kingdom Hearts games."));
|
||||
"Disables accurate GS Memory Clearing to be done on the CPU, and let the GPU handle it, which can help Kingdom Hearts "
|
||||
"games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.disablePartialInvalidation, tr("Disable Partial Invalidation"), tr("Unchecked"),
|
||||
tr("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise. "
|
||||
@@ -508,13 +537,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.roundSprite, tr("Round Sprite"), tr("Off (Default)"),
|
||||
tr("Corrects the sampling of 2D sprite textures when upscaling. "
|
||||
"Fixes lines in sprites of games like Ar tonelico when upscaling. Half option is for flat sprites, Full is for all sprites."));
|
||||
"Fixes lines in sprites of games like Ar tonelico when upscaling. Half option is for flat sprites, Full is for all "
|
||||
"sprites."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureOffsetX, tr("Texture Offsets X"), tr("0"),
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment too."));
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment "
|
||||
"too."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureOffsetY, tr("Texture Offsets Y"), tr("0"),
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment too."));
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment "
|
||||
"too."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.alignSprite, tr("Align Sprite"), tr("Unchecked"),
|
||||
tr("Fixes issues with upscaling(vertical lines) in Namco games like Ace Combat, Tekken, Soul Calibur, etc."));
|
||||
@@ -548,10 +580,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.casSharpness, tr("Sharpness"), tr("50%"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.shadeBoost, tr("Shade Boost"), tr("Unchecked"),
|
||||
tr("Enables saturation, contrast, and brightness to be adjusted. Values of brightness, saturation, and contrast are at default 50."));
|
||||
tr("Enables saturation, contrast, and brightness to be adjusted. Values of brightness, saturation, and contrast are at default "
|
||||
"50."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fxaa, tr("FXAA"), tr("Unchecked"),
|
||||
tr("Applies the FXAA anti-aliasing algorithm to improve the visual quality of games."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.fxaa, tr("FXAA"), tr("Unchecked"), tr("Applies the FXAA anti-aliasing algorithm to improve the visual quality of games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.shadeBoostBrightness, tr("Brightness"), tr("50"), tr(""));
|
||||
|
||||
@@ -564,8 +597,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
// OSD tab
|
||||
{
|
||||
dialog->registerWidgetHelp(m_ui.osdScale, tr("OSD Scale"), tr("100%"),
|
||||
tr("Scales the size of the onscreen OSD from 100% to 500%."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 100% to 500%."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowMessages, tr("Show OSD Messages"), tr("Checked"),
|
||||
tr("Shows on-screen-display messages when events occur such as save states being "
|
||||
@@ -580,11 +613,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.osdShowResolution, tr("Show Resolution"), tr("Unchecked"),
|
||||
tr("Shows the resolution of the game in the top-right corner of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowCPU, tr("Show CPU Usage"), tr("Unchecked"),
|
||||
tr("Shows host's CPU utilization."));
|
||||
dialog->registerWidgetHelp(m_ui.osdShowCPU, tr("Show CPU Usage"), tr("Unchecked"), tr("Shows host's CPU utilization."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGPU, tr("Show GPU Usage"), tr("Unchecked"),
|
||||
tr("Shows host's GPU utilization."));
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGPU, tr("Show GPU Usage"), tr("Unchecked"), tr("Shows host's GPU utilization."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGSStats, tr("Show Statistics"), tr("Unchecked"),
|
||||
tr("Shows counters for internal graphical utilization, useful for debugging."));
|
||||
@@ -593,16 +624,26 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Shows OSD icon indicators for emulation states such as Pausing, Turbo, Fast Forward, and Slow Motion."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"),
|
||||
tr("Displays various settings and the current values of those settings, useful for debugging."));
|
||||
tr("Displays various settings and the current values of those settings, useful for debugging."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"),
|
||||
tr("Shows the current controler state of the system in the bottom left corner of the display."));
|
||||
tr("Shows the current controler state of the system in the bottom left corner of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"),
|
||||
tr("Displays a graph showing the average frametimes."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr("Displays a graph showing the average frametimes."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"),
|
||||
tr("Checked"), tr("Displays warnings when settings are enabled which may break games."));
|
||||
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"), tr("Checked"),
|
||||
tr("Displays warnings when settings are enabled which may break games."));
|
||||
}
|
||||
|
||||
// Recording tab
|
||||
{
|
||||
dialog->registerWidgetHelp(m_ui.enableVideoCaptureArguments, tr("Enable Extra Arguments"), tr("Unchecked"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.videoCaptureArguments, tr("Extra Arguments"), tr("Leave It Blank"),
|
||||
tr("Parameters passed to selected video codec.<br> "
|
||||
"You must use '=' to separate key from value and ':' to separate two pairs from each other.<br> "
|
||||
"For example: \"crf = 21 : preset = veryfast\""));
|
||||
}
|
||||
|
||||
// Advanced tab
|
||||
@@ -627,8 +668,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Frame Buffer Fetch"), tr("Unchecked"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
|
||||
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still rendered, it just means "
|
||||
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU are near maximum "
|
||||
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
|
||||
"rendered, it just means "
|
||||
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU "
|
||||
"are near maximum "
|
||||
"utilization, but makes frame pacing more inconsistent and can increase input lag."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Disable Threaded Presentation"), tr("Unchecked"),
|
||||
@@ -707,9 +750,8 @@ void GraphicsSettingsWidget::onFullscreenModeChanged(int index)
|
||||
|
||||
void GraphicsSettingsWidget::onTrilinearFilteringChanged()
|
||||
{
|
||||
const bool forced_bilinear =
|
||||
(m_dialog->getEffectiveIntValue("EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic))
|
||||
>= static_cast<int>(TriFiltering::Forced));
|
||||
const bool forced_bilinear = (m_dialog->getEffectiveIntValue("EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic)) >=
|
||||
static_cast<int>(TriFiltering::Forced));
|
||||
m_ui.textureFiltering->setDisabled(forced_bilinear);
|
||||
}
|
||||
|
||||
@@ -721,16 +763,15 @@ void GraphicsSettingsWidget::onShadeBoostChanged()
|
||||
m_ui.shadeBoostSaturation->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onVideoCaptureContainerChanged()
|
||||
void GraphicsSettingsWidget::onCaptureContainerChanged()
|
||||
{
|
||||
const std::string container(
|
||||
m_dialog->getEffectiveStringValue("EmuCore/GS", "VideoCaptureContainer", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_CONTAINER));
|
||||
m_dialog->getEffectiveStringValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER));
|
||||
|
||||
m_ui.videoCaptureCodec->disconnect();
|
||||
m_ui.videoCaptureCodec->clear();
|
||||
const std::vector<std::pair<std::string, std::string>> vcapture_formats(GSCapture::GetVideoCodecList(container.c_str()));
|
||||
m_ui.videoCaptureCodec->addItem(tr("Default"), QString());
|
||||
for (const auto& [format, name] : vcapture_formats)
|
||||
for (const auto& [format, name] : GSCapture::GetVideoCodecList(container.c_str()))
|
||||
{
|
||||
const QString qformat(QString::fromStdString(format));
|
||||
const QString qname(QString::fromStdString(name));
|
||||
@@ -739,6 +780,50 @@ void GraphicsSettingsWidget::onVideoCaptureContainerChanged()
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(
|
||||
m_dialog->getSettingsInterface(), m_ui.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
|
||||
|
||||
m_ui.audioCaptureCodec->disconnect();
|
||||
m_ui.audioCaptureCodec->clear();
|
||||
m_ui.audioCaptureCodec->addItem(tr("Default"), QString());
|
||||
for (const auto& [format, name] : GSCapture::GetAudioCodecList(container.c_str()))
|
||||
{
|
||||
const QString qformat(QString::fromStdString(format));
|
||||
const QString qname(QString::fromStdString(name));
|
||||
m_ui.audioCaptureCodec->addItem(QStringLiteral("%1 [%2]").arg(qformat).arg(qname), qformat);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(
|
||||
m_dialog->getSettingsInterface(), m_ui.audioCaptureCodec, "EmuCore/GS", "AudioCaptureCodec");
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableVideoCaptureChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCapture", true);
|
||||
m_ui.videoCaptureOptions->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableVideoCaptureArgumentsChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCaptureParameters", false);
|
||||
m_ui.videoCaptureArguments->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onVideoCaptureAutoResolutionChanged()
|
||||
{
|
||||
const bool enabled = !m_dialog->getEffectiveBoolValue("EmuCore/GS", "VideoCaptureAutoResolution", true);
|
||||
m_ui.videoCaptureWidth->setEnabled(enabled);
|
||||
m_ui.videoCaptureHeight->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableAudioCaptureChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableAudioCapture", true);
|
||||
m_ui.audioCaptureOptions->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableAudioCaptureParameters", false);
|
||||
m_ui.audioCaptureArguments->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onGpuPaletteConversionChanged(int state)
|
||||
@@ -767,7 +852,8 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
const bool is_sw_dx = false;
|
||||
#endif
|
||||
|
||||
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL || type == GSRendererType::VK || type == GSRendererType::Metal);
|
||||
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL ||
|
||||
type == GSRendererType::VK || type == GSRendererType::Metal);
|
||||
const bool is_software = (type == GSRendererType::SW);
|
||||
const bool hw_fixes = (is_hardware && m_ui.enableHWFixes->checkState() == Qt::Checked);
|
||||
const int prev_tab = m_ui.tabs->currentIndex();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -43,7 +43,12 @@ private Q_SLOTS:
|
||||
void onGpuPaletteConversionChanged(int state);
|
||||
void onFullscreenModeChanged(int index);
|
||||
void onShadeBoostChanged();
|
||||
void onVideoCaptureContainerChanged();
|
||||
void onCaptureContainerChanged();
|
||||
void onEnableVideoCaptureChanged();
|
||||
void onEnableVideoCaptureArgumentsChanged();
|
||||
void onVideoCaptureAutoResolutionChanged();
|
||||
void onEnableAudioCaptureChanged();
|
||||
void onEnableAudioCaptureArgumentsChanged();
|
||||
|
||||
private:
|
||||
GSRendererType getEffectiveRenderer() const;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>861</width>
|
||||
<height>501</height>
|
||||
<width>720</width>
|
||||
<height>466</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -1649,6 +1649,285 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="recordingTab">
|
||||
<attribute name="title">
|
||||
<string>Recording</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="videoDumpDirectory">
|
||||
<property name="title">
|
||||
<string>Video Dumping Directory</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="videoDumpingDirectory"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoDumpingDirectoryBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoDumpingDirectoryOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoDumpingDirectoryReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Capture Setup</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="captureContainerLabel">
|
||||
<property name="text">
|
||||
<string>Container:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="captureContainer"/>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_10" columnstretch="1,1">
|
||||
<property name="horizontalSpacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="audioCaptureOptions" native="true">
|
||||
<layout class="QFormLayout" name="formLayout_10">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="audioCaptureCodecLabel">
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="audioCaptureCodec"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="audioCaptureBitrateLabel">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="audioCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2048</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="enableAudioCaptureArguments">
|
||||
<property name="text">
|
||||
<string>Extra Arguments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="audioCaptureArguments"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="enableAudioCapture">
|
||||
<property name="text">
|
||||
<string>Capture Audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="videoCaptureOptions" native="true">
|
||||
<layout class="QFormLayout" name="formLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="videoCaptureCodecLabel">
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="videoCaptureCodec"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="videoCaptureBitrateLabel">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="videoCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="videoCaptureResolutionLabel">
|
||||
<property name="text">
|
||||
<string>Resolution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="1,0,1,0">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureWidth">
|
||||
<property name="minimum">
|
||||
<number>320</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>640</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_46">
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureHeight">
|
||||
<property name="minimum">
|
||||
<number>240</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>240</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="videoCaptureResolutionAuto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="enableVideoCaptureArguments">
|
||||
<property name="text">
|
||||
<string>Extra Arguments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="videoCaptureArguments"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="enableVideoCapture">
|
||||
<property name="text">
|
||||
<string>Capture Video</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="advancedTab">
|
||||
<attribute name="title">
|
||||
<string>Advanced</string>
|
||||
@@ -1742,46 +2021,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_45">
|
||||
<property name="text">
|
||||
<string>Video Capture Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0,0,0">
|
||||
<item>
|
||||
<widget class="QComboBox" name="videoCaptureCodec"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="videoCaptureContainer"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_46">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Settings/ControllerSettingWidgetBinder.h"
|
||||
#include "Settings/InputBindingDialog.h"
|
||||
#include "Settings/InputBindingWidget.h"
|
||||
#include <QtCore/QTimer>
|
||||
@@ -24,6 +25,8 @@
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QWheelEvent>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
// _BitScanForward()
|
||||
#include "pcsx2/GS/GSIntrin.h"
|
||||
|
||||
@@ -45,6 +48,26 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
|
||||
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
|
||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
|
||||
updateList();
|
||||
|
||||
// Only show the sensitivity controls for binds where it's applicable.
|
||||
if (bind_type == InputBindingInfo::Type::Button || bind_type == InputBindingInfo::Type::Axis ||
|
||||
bind_type == InputBindingInfo::Type::HalfAxis)
|
||||
{
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
sif, m_ui.sensitivity, m_section_name, fmt::format("{}Scale", m_key_name), 100.0f, 1.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
sif, m_ui.deadzone, m_section_name, fmt::format("{}Deadzone", m_key_name), 100.0f, 0.0f);
|
||||
|
||||
connect(m_ui.sensitivity, &QSlider::valueChanged, this, &InputBindingDialog::onSensitivityChanged);
|
||||
connect(m_ui.deadzone, &QSlider::valueChanged, this, &InputBindingDialog::onDeadzoneChanged);
|
||||
|
||||
onSensitivityChanged(m_ui.sensitivity->value());
|
||||
onDeadzoneChanged(m_ui.deadzone->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.verticalLayout->removeWidget(m_ui.sensitivityWidget);
|
||||
}
|
||||
}
|
||||
|
||||
InputBindingDialog::~InputBindingDialog()
|
||||
@@ -318,6 +341,16 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val
|
||||
}
|
||||
}
|
||||
|
||||
void InputBindingDialog::onSensitivityChanged(int value)
|
||||
{
|
||||
m_ui.sensitivityValue->setText(tr("%1%").arg(value));
|
||||
}
|
||||
|
||||
void InputBindingDialog::onDeadzoneChanged(int value)
|
||||
{
|
||||
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
|
||||
}
|
||||
|
||||
void InputBindingDialog::hookInputManager()
|
||||
{
|
||||
InputManager::SetHook([this](InputBindingKey key, float value) {
|
||||
|
||||
@@ -41,6 +41,9 @@ protected Q_SLOTS:
|
||||
void onInputListenTimerTimeout();
|
||||
void inputManagerHookCallback(InputBindingKey key, float value);
|
||||
|
||||
void onSensitivityChanged(int value);
|
||||
void onDeadzoneChanged(int value);
|
||||
|
||||
protected:
|
||||
enum : u32
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>533</width>
|
||||
<height>283</height>
|
||||
<height>266</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -30,6 +30,93 @@
|
||||
<item>
|
||||
<widget class="QListWidget" name="bindingList"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="sensitivityWidget" native="true">
|
||||
<layout class="QGridLayout" name="sensitivityLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="sensitivityLabel">
|
||||
<property name="text">
|
||||
<string>Sensitivity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="sensitivity">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="sensitivityValue">
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="deadzoneLabel">
|
||||
<property name="text">
|
||||
<string>Deadzone:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="deadzone">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="deadzoneValue">
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="status">
|
||||
<property name="text">
|
||||
|
||||
@@ -98,7 +98,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
AutoUpdaterDialog::getDefaultTag());
|
||||
|
||||
m_ui.autoUpdateCurrentVersion->setText(tr("%1 (%2)").arg(AutoUpdaterDialog::getCurrentVersion()).arg(AutoUpdaterDialog::getCurrentVersionDate()));
|
||||
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true); });
|
||||
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true, true); });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -191,7 +191,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
||||
m_ui.settingsContainer->setCurrentIndex(0);
|
||||
m_ui.helpText->setText(m_category_help_text[0]);
|
||||
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
|
||||
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::accept);
|
||||
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::close);
|
||||
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -71,6 +71,8 @@
|
||||
<FloatingPointModel>Precise</FloatingPointModel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<!-- Current Qt debug builds assert on RTTI. Remove this once we next build Qt. -->
|
||||
<RuntimeTypeInfo Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Debug))">true</RuntimeTypeInfo>
|
||||
<AdditionalOptions>/Zc:__cplusplus /Zo /utf-8%(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@
|
||||
#include "Elfheader.h"
|
||||
#include "ps2/BiosTools.h"
|
||||
#include "Recording/InputRecording.h"
|
||||
#include "VMManager.h"
|
||||
#include "Host.h"
|
||||
|
||||
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
|
||||
// (examples: SLUS-2113, etc).
|
||||
@@ -2440,8 +2440,8 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
|
||||
|
||||
|
||||
case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
|
||||
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Resetting VM.");
|
||||
VMManager::Reset();
|
||||
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Shutting down VM.");
|
||||
Host::RequestVMShutdown(false, false, false);
|
||||
break;
|
||||
|
||||
case 0x12: // sceCdReadILinkId (0:9)
|
||||
|
||||
@@ -430,9 +430,7 @@ bool DoCDVDopen()
|
||||
|
||||
Host::AddKeyedOSDMessage("BlockDumpCreate", fmt::format("Saving CDVD block dump to '{}'.", temp), Host::OSD_INFO_DURATION);
|
||||
|
||||
blockDumpFile.Create(std::move(temp), 2);
|
||||
|
||||
if (blockDumpFile.IsOpened())
|
||||
if (blockDumpFile.Create(std::move(temp), 2))
|
||||
{
|
||||
int blockofs = 0;
|
||||
uint blocksize = CD_FRAMESIZE_RAW;
|
||||
|
||||
@@ -51,15 +51,8 @@ s32 CALLBACK ISOopen(const char* pTitle)
|
||||
return -1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
iso.Open(pTitle);
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
if (!iso.Open(pTitle))
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (iso.GetType())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include <IOKit/storage/IOMedia.h>
|
||||
#include <IOKit/storage/IOCDMedia.h>
|
||||
#include <IOKit/storage/IODVDMedia.h>
|
||||
#include <IOKit/IOBSD.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
std::vector<std::string> GetDriveListFromClasses(CFMutableDictionaryRef classes)
|
||||
{
|
||||
io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
kern_return_t result;
|
||||
std::vector<std::string> drives;
|
||||
|
||||
CFDictionarySetValue(classes, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
|
||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classes, &iterator);
|
||||
if (result != KERN_SUCCESS)
|
||||
return drives;
|
||||
while (io_object_t media = IOIteratorNext(iterator))
|
||||
{
|
||||
CFTypeRef path_cfstr = IORegistryEntryCreateCFProperty(media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
|
||||
if (path_cfstr)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
strlcpy(path, "/dev/r", PATH_MAX);
|
||||
size_t path_prefix_len = strnlen(path, PATH_MAX);
|
||||
result = CFStringGetCString((CFStringRef)path_cfstr, path + path_prefix_len, PATH_MAX - path_prefix_len, kCFStringEncodingUTF8);
|
||||
if (result)
|
||||
{
|
||||
drives.emplace_back(path);
|
||||
}
|
||||
CFRelease(path_cfstr);
|
||||
}
|
||||
IOObjectRelease(media);
|
||||
}
|
||||
IOObjectRelease(iterator);
|
||||
return drives;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<std::string> GetOpticalDriveList()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
std::vector<std::string> drives;
|
||||
|
||||
if (CFMutableDictionaryRef cd_classes = IOServiceMatching(kIOCDMediaClass))
|
||||
{
|
||||
std::vector<std::string> cd = GetDriveListFromClasses(cd_classes);
|
||||
drives.insert(drives.end(), cd.begin(), cd.end());
|
||||
}
|
||||
|
||||
if (CFMutableDictionaryRef dvd_classes = IOServiceMatching(kIODVDMediaClass))
|
||||
{
|
||||
std::vector<std::string> dvd = GetDriveListFromClasses(dvd_classes);
|
||||
drives.insert(drives.end(), dvd.begin(), dvd.end());
|
||||
}
|
||||
return drives;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetValidDrive(std::string& drive)
|
||||
{
|
||||
if (!drive.empty())
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd != -1)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
drive.clear();
|
||||
}
|
||||
#else
|
||||
drive.clear();
|
||||
#endif
|
||||
}
|
||||
if (drive.empty())
|
||||
{
|
||||
auto drives = GetOpticalDriveList();
|
||||
if (!drives.empty())
|
||||
drive = drives.front();
|
||||
}
|
||||
if (!drive.empty())
|
||||
DevCon.WriteLn("CDVD: Opening drive '%s'...", drive.c_str());
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <IOKit/storage/IOCDMediaBSDClient.h>
|
||||
#include <IOKit/storage/IODVDMediaBSDClient.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
IOCtlSrc::IOCtlSrc(decltype(m_filename) filename)
|
||||
: m_filename(filename)
|
||||
{
|
||||
if (!Reopen())
|
||||
throw std::runtime_error(" * CDVD: Error opening source.\n");
|
||||
}
|
||||
|
||||
IOCtlSrc::~IOCtlSrc()
|
||||
{
|
||||
if (m_device != -1)
|
||||
{
|
||||
SetSpindleSpeed(true);
|
||||
close(m_device);
|
||||
}
|
||||
}
|
||||
|
||||
bool IOCtlSrc::Reopen()
|
||||
{
|
||||
if (m_device != -1)
|
||||
close(m_device);
|
||||
|
||||
// O_NONBLOCK allows a valid file descriptor to be returned even if the
|
||||
// drive is empty. Probably does other things too.
|
||||
m_device = open(m_filename.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
// DVD detection MUST be first on Linux - The TOC ioctls work for both
|
||||
// CDs and DVDs.
|
||||
if (ReadDVDInfo() || ReadCDInfo())
|
||||
SetSpindleSpeed(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IOCtlSrc::SetSpindleSpeed(bool restore_defaults) const
|
||||
{
|
||||
u16 speed = restore_defaults ? 0xFFFF : m_media_type >= 0 ? 5540 :
|
||||
3600;
|
||||
int ioctl_code = m_media_type >= 0 ? DKIOCDVDSETSPEED : DKIOCCDSETSPEED;
|
||||
if (ioctl(m_device, ioctl_code, &speed) == -1)
|
||||
{
|
||||
DevCon.Warning("CDVD: Failed to set spindle speed: %s", strerror(errno));
|
||||
}
|
||||
else if (!restore_defaults)
|
||||
{
|
||||
DevCon.WriteLn("CDVD: Spindle speed set to %d", speed);
|
||||
}
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetSectorCount() const
|
||||
{
|
||||
return m_sectors;
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetLayerBreakAddress() const
|
||||
{
|
||||
return m_layer_break;
|
||||
}
|
||||
|
||||
s32 IOCtlSrc::GetMediaType() const
|
||||
{
|
||||
return m_media_type;
|
||||
}
|
||||
|
||||
const std::vector<toc_entry>& IOCtlSrc::ReadTOC() const
|
||||
{
|
||||
return m_toc;
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
const ssize_t bytes_to_read = 2048 * count;
|
||||
ssize_t bytes_read = pread(m_device, buffer, bytes_to_read, sector * 2048ULL);
|
||||
if (bytes_read == bytes_to_read)
|
||||
return true;
|
||||
|
||||
if (bytes_read == -1)
|
||||
DevCon.Warning("CDVD: read sectors %u-%u failed: %s",
|
||||
sector, sector + count - 1, strerror(errno));
|
||||
else
|
||||
DevCon.Warning("CDVD: read sectors %u-%u: %zd bytes read, %zd bytes expected",
|
||||
sector, sector + count - 1, bytes_read, bytes_to_read);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
dk_cd_read_t desc;
|
||||
memset(&desc, 0, sizeof(dk_cd_read_t));
|
||||
desc.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader | kCDSectorAreaSubHeader | kCDSectorAreaUser | kCDSectorAreaAuxiliary;
|
||||
desc.sectorType = kCDSectorTypeUnknown;
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
desc.offset = (sector + i) * 2352ULL;
|
||||
desc.buffer = buffer + i * 2352;
|
||||
desc.bufferLength = 2352;
|
||||
if (ioctl(m_device, DKIOCCDREAD, &desc) == -1)
|
||||
{
|
||||
DevCon.Warning("CDVD: DKIOCCDREAD sector %u failed: %s",
|
||||
sector + i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadDVDInfo()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
dk_dvd_read_structure_t dvdrs;
|
||||
memset(&dvdrs, 0, sizeof(dk_dvd_read_structure_t));
|
||||
dvdrs.format = kDVDStructureFormatPhysicalFormatInfo;
|
||||
dvdrs.layer = 0;
|
||||
|
||||
DVDPhysicalFormatInfo layer0;
|
||||
dvdrs.buffer = &layer0;
|
||||
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
|
||||
|
||||
int ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
|
||||
if (ret == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 start_sector = *(u32*)layer0.startingPhysicalSectorNumberOfDataArea;
|
||||
u32 end_sector = *(u32*)layer0.endPhysicalSectorNumberOfDataArea;
|
||||
if (layer0.numberOfLayers == 0)
|
||||
{
|
||||
// Single layer
|
||||
m_media_type = 0;
|
||||
m_layer_break = 0;
|
||||
m_sectors = end_sector - start_sector + 1;
|
||||
}
|
||||
else if (layer0.trackPath == 0)
|
||||
{
|
||||
// Dual layer, Parallel Track Path
|
||||
DVDPhysicalFormatInfo layer1;
|
||||
dvdrs.layer = 1;
|
||||
dvdrs.buffer = &layer1;
|
||||
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
|
||||
ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
|
||||
if (ret == -1)
|
||||
return false;
|
||||
u32 layer1_start_sector = *(u32*)layer1.startingPhysicalSectorNumberOfDataArea;
|
||||
u32 layer1_end_sector = *(u32*)layer1.endPhysicalSectorNumberOfDataArea;
|
||||
|
||||
m_media_type = 1;
|
||||
m_layer_break = end_sector - start_sector;
|
||||
m_sectors = end_sector - start_sector + 1 + layer1_end_sector - layer1_start_sector + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dual layer, Opposite Track Path
|
||||
u32 end_sector_layer0 = *(u32*)layer0.endSectorNumberInLayerZero;
|
||||
m_media_type = 2;
|
||||
m_layer_break = end_sector_layer0 - start_sector;
|
||||
m_sectors = end_sector_layer0 - start_sector + 1 + end_sector - (~end_sector_layer0 & 0xFFFFFFU) + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadCDInfo()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
u8* buffer = (u8*)malloc(2048);
|
||||
dk_cd_read_toc_t cdrt;
|
||||
memset(&cdrt, 0, sizeof(dk_cd_read_toc_t));
|
||||
cdrt.format = kCDTOCFormatTOC;
|
||||
cdrt.formatAsTime = 1;
|
||||
cdrt.address.track = 0;
|
||||
cdrt.buffer = buffer;
|
||||
cdrt.bufferLength = 2048;
|
||||
memset(buffer, 0, 2048);
|
||||
|
||||
if (ioctl(m_device, DKIOCCDREADTOC, &cdrt) == -1)
|
||||
{
|
||||
DevCon.Warning("CDVD: DKIOCCDREADTOC failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
CDTOC* toc = (CDTOC*)buffer;
|
||||
|
||||
u32 desc_count = CDTOCGetDescriptorCount(toc);
|
||||
|
||||
for (u32 i = 0; i < desc_count; ++i)
|
||||
{
|
||||
CDTOCDescriptor desc = toc->descriptors[i];
|
||||
if (desc.point < 0xa0 && desc.adr == 1)
|
||||
{
|
||||
u32 lba = CDConvertMSFToLBA(desc.p);
|
||||
m_toc.push_back({lba, desc.point, desc.adr, desc.control});
|
||||
}
|
||||
else if (desc.point == 0xa2) // lead out, use to get total sector count
|
||||
{
|
||||
m_sectors = CDConvertMSFToLBA(desc.p);
|
||||
}
|
||||
}
|
||||
|
||||
m_media_type = -1;
|
||||
|
||||
free(buffer);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::DiscReady()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
if (!m_sectors)
|
||||
{
|
||||
Reopen();
|
||||
}
|
||||
|
||||
return !!m_sectors;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -293,7 +293,7 @@ bool GzippedFileReader::OkIndex()
|
||||
Console.Warning("This may take a while (but only once). Scanning compressed file to generate a quick access index...");
|
||||
|
||||
const s64 prevoffset = FileSystem::FTell64(m_src);
|
||||
Access* index;
|
||||
Access* index = nullptr;
|
||||
int len = build_index(m_src, GZFILE_SPAN_DEFAULT, &index);
|
||||
printf("\n"); // build_index prints progress without \n's
|
||||
FileSystem::FSeek64(m_src, prevoffset, SEEK_SET);
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "IsoFileFormats.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Exceptions.h"
|
||||
|
||||
#include "CDVD/IsoFileFormats.h"
|
||||
#include "Config.h"
|
||||
#include "Host.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include "fmt/format.h"
|
||||
|
||||
static const char* nameFromType(int type)
|
||||
{
|
||||
@@ -246,12 +246,17 @@ bool InputIsoFile::Open(std::string srcfile, bool testOnly)
|
||||
bool detected = Detect();
|
||||
|
||||
if (testOnly)
|
||||
{
|
||||
Close();
|
||||
return detected;
|
||||
}
|
||||
|
||||
if (!detected)
|
||||
throw Exception::BadStream()
|
||||
.SetUserMsg("Unrecognized ISO image file format.")
|
||||
.SetDiagMsg("ISO mounting failed: PCSX2 is unable to identify the ISO image type.");
|
||||
{
|
||||
Console.Error(fmt::format("Unable to identify the ISO image type for '{}'", srcfile));
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isBlockdump && !isCompressed)
|
||||
{
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
return m_filename;
|
||||
}
|
||||
|
||||
void Create(std::string filename, int mode);
|
||||
bool Create(std::string filename, int mode);
|
||||
void Close();
|
||||
|
||||
void WriteHeader(int blockofs, uint blocksize, uint blocks);
|
||||
|
||||
@@ -16,18 +16,14 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <libudev.h>
|
||||
#include <linux/cdrom.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
std::vector<std::string> GetOpticalDriveList()
|
||||
{
|
||||
#ifdef __linux__
|
||||
udev* udev_context = udev_new();
|
||||
if (!udev_context)
|
||||
return {};
|
||||
@@ -56,16 +52,12 @@ std::vector<std::string> GetOpticalDriveList()
|
||||
udev_unref(udev_context);
|
||||
|
||||
return drives;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetValidDrive(std::string& drive)
|
||||
{
|
||||
if (!drive.empty())
|
||||
{
|
||||
#ifdef __linux__
|
||||
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd != -1)
|
||||
{
|
||||
@@ -77,9 +69,6 @@ void GetValidDrive(std::string& drive)
|
||||
{
|
||||
drive.clear();
|
||||
}
|
||||
#else
|
||||
drive.clear();
|
||||
#endif
|
||||
}
|
||||
if (drive.empty())
|
||||
{
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/cdrom.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
@@ -108,7 +105,6 @@ bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
|
||||
|
||||
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
#ifdef __linux__
|
||||
union
|
||||
{
|
||||
cdrom_msf msf;
|
||||
@@ -130,14 +126,10 @@ bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadDVDInfo()
|
||||
{
|
||||
#ifdef __linux__
|
||||
dvd_struct dvdrs;
|
||||
dvdrs.type = DVD_STRUCT_PHYSICAL;
|
||||
dvdrs.physical.layer_num = 0;
|
||||
@@ -180,14 +172,10 @@ bool IOCtlSrc::ReadDVDInfo()
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadCDInfo()
|
||||
{
|
||||
#ifdef __linux__
|
||||
cdrom_tochdr header;
|
||||
|
||||
if (ioctl(m_device, CDROMREADTOCHDR, &header) == -1)
|
||||
@@ -214,14 +202,10 @@ bool IOCtlSrc::ReadCDInfo()
|
||||
m_media_type = -1;
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::DiscReady()
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
@@ -239,7 +223,4 @@ bool IOCtlSrc::DiscReady()
|
||||
}
|
||||
|
||||
return !!m_sectors;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "IsoFileFormats.h"
|
||||
#include "CDVD/IsoFileFormats.h"
|
||||
#include "Host.h"
|
||||
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
@@ -44,7 +46,7 @@ void OutputIsoFile::_init()
|
||||
m_blocks = 0;
|
||||
}
|
||||
|
||||
void OutputIsoFile::Create(std::string filename, int version)
|
||||
bool OutputIsoFile::Create(std::string filename, int version)
|
||||
{
|
||||
Close();
|
||||
m_filename = std::move(filename);
|
||||
@@ -57,11 +59,13 @@ void OutputIsoFile::Create(std::string filename, int version)
|
||||
m_outstream = FileSystem::OpenCFile(m_filename.c_str(), "wb");
|
||||
if (!m_outstream)
|
||||
{
|
||||
Console.Error("(OutputIsoFile::Create) Unable to open the file '%s' for writing: %d", m_filename.c_str(), errno);
|
||||
Exception::FromErrno(filename, errno)->Rethrow();
|
||||
Console.Error(fmt::format("(OutputIsoFile::Create) Unable to open the file '{}' for writing: {}", m_filename, errno));
|
||||
_init();
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn("isoFile create ok: %s ", m_filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generates format header information for blockdumps.
|
||||
@@ -122,16 +126,8 @@ void OutputIsoFile::WriteBuffer(const void* src, size_t size)
|
||||
{
|
||||
if (std::fwrite(src, size, 1, m_outstream) != 1)
|
||||
{
|
||||
int err = errno;
|
||||
if (!err)
|
||||
{
|
||||
throw Exception::BadStream(m_filename)
|
||||
.SetDiagMsg(fmt::format("An error occurred while writing {} bytes to file", size));
|
||||
}
|
||||
|
||||
std::unique_ptr<BaseException> ex(Exception::FromErrno(m_filename, err));
|
||||
ex->SetDiagMsg(fmt::format("An error occurred while writing {} bytes to file: {}", size, ex->DiagMsg()));
|
||||
ex->Rethrow();
|
||||
Host::ReportErrorAsync("Write Error", fmt::format("errno {} when trying to write {} bytes to block dump file.\n\nClosing file."));
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-20
@@ -150,6 +150,7 @@ set(pcsx2Sources
|
||||
Vif_Codes.cpp
|
||||
Vif_Transfer.cpp
|
||||
Vif_Unpack.cpp
|
||||
VirtualMemory.cpp
|
||||
vtlb.cpp
|
||||
VU0.cpp
|
||||
VUmicro.cpp
|
||||
@@ -201,7 +202,6 @@ set(pcsx2Headers
|
||||
PerformanceMetrics.h
|
||||
PrecompiledHeader.h
|
||||
R3000A.h
|
||||
R5900Exceptions.h
|
||||
R5900.h
|
||||
R5900OpcodeTables.h
|
||||
SaveState.h
|
||||
@@ -217,6 +217,7 @@ set(pcsx2Headers
|
||||
Vif_Dma.h
|
||||
Vif.h
|
||||
Vif_Unpack.h
|
||||
VirtualMemory.h
|
||||
vtlb.h
|
||||
VUflags.h
|
||||
VUmicro.h
|
||||
@@ -328,6 +329,7 @@ set(pcsx2DEV9Sources
|
||||
DEV9/InternalServers/DNS_Logger.cpp
|
||||
DEV9/InternalServers/DNS_Server.cpp
|
||||
DEV9/PacketReader/ARP/ARP_Packet.cpp
|
||||
DEV9/PacketReader/ARP/ARP_PacketEditor.cpp
|
||||
DEV9/PacketReader/IP/ICMP/ICMP_Packet.cpp
|
||||
DEV9/PacketReader/IP/TCP/TCP_Options.cpp
|
||||
DEV9/PacketReader/IP/TCP/TCP_Packet.cpp
|
||||
@@ -339,7 +341,7 @@ set(pcsx2DEV9Sources
|
||||
DEV9/PacketReader/IP/IP_Options.cpp
|
||||
DEV9/PacketReader/IP/IP_Packet.cpp
|
||||
DEV9/PacketReader/EthernetFrame.cpp
|
||||
DEV9/PacketReader/NetLib.cpp
|
||||
DEV9/PacketReader/EthernetFrameEditor.cpp
|
||||
DEV9/Sessions/BaseSession.cpp
|
||||
DEV9/Sessions/ICMP_Session/ICMP_Session.cpp
|
||||
DEV9/Sessions/TCP_Session/TCP_Session.cpp
|
||||
@@ -366,6 +368,7 @@ set(pcsx2DEV9Headers
|
||||
DEV9/InternalServers/DNS_Server.h
|
||||
DEV9/net.h
|
||||
DEV9/PacketReader/ARP/ARP_Packet.h
|
||||
DEV9/PacketReader/ARP/ARP_PacketEditor.h
|
||||
DEV9/PacketReader/IP/ICMP/ICMP_Packet.h
|
||||
DEV9/PacketReader/IP/TCP/TCP_Options.h
|
||||
DEV9/PacketReader/IP/TCP/TCP_Packet.h
|
||||
@@ -380,6 +383,8 @@ set(pcsx2DEV9Headers
|
||||
DEV9/PacketReader/IP/IP_Packet.h
|
||||
DEV9/PacketReader/IP/IP_Payload.h
|
||||
DEV9/PacketReader/EthernetFrame.h
|
||||
DEV9/PacketReader/EthernetFrameEditor.h
|
||||
DEV9/PacketReader/MAC_Address.h
|
||||
DEV9/PacketReader/NetLib.h
|
||||
DEV9/PacketReader/Payload.h
|
||||
DEV9/pcap_io.h
|
||||
@@ -431,8 +436,6 @@ set(pcsx2USBHeaders
|
||||
USB/qemu-usb/input-keymap.h
|
||||
USB/qemu-usb/queue.h
|
||||
USB/qemu-usb/qusb.h
|
||||
USB/readerwriterqueue/atomicops.h
|
||||
USB/readerwriterqueue/readerwriterqueue.h
|
||||
USB/shared/ringbuffer.h
|
||||
USB/usb-eyetoy/jo_mpeg.h
|
||||
USB/usb-eyetoy/ov519.h
|
||||
@@ -496,7 +499,6 @@ set(pcsx2GSSources
|
||||
GS/GSAlignedClass.cpp
|
||||
GS/GSCapture.cpp
|
||||
GS/GSClut.cpp
|
||||
GS/GSCodeBuffer.cpp
|
||||
GS/GSCrc.cpp
|
||||
GS/GSDrawingContext.cpp
|
||||
GS/GSDump.cpp
|
||||
@@ -531,12 +533,10 @@ set(pcsx2GSSources
|
||||
|
||||
# GS headers
|
||||
set(pcsx2GSHeaders
|
||||
GS/config.h
|
||||
GS/GSAlignedClass.h
|
||||
GS/GSBlock.h
|
||||
GS/GSCapture.h
|
||||
GS/GSClut.h
|
||||
GS/GSCodeBuffer.h
|
||||
GS/GSCrc.h
|
||||
GS/GSDrawingContext.h
|
||||
GS/GSDrawingEnvironment.h
|
||||
@@ -687,8 +687,6 @@ set(pcsx2IPUSources
|
||||
set(pcsx2IPUSourcesUnshared
|
||||
IPU/IPU_MultiISA.cpp
|
||||
IPU/IPUdither.cpp
|
||||
IPU/mpeg2lib/Idct.cpp
|
||||
IPU/mpeg2lib/Mpeg.cpp
|
||||
IPU/yuv2rgb.cpp
|
||||
)
|
||||
|
||||
@@ -698,8 +696,7 @@ set(pcsx2IPUHeaders
|
||||
IPU/IPU_Fifo.h
|
||||
IPU/IPU_MultiISA.h
|
||||
IPU/IPUdma.h
|
||||
IPU/mpeg2lib/Mpeg.h
|
||||
IPU/mpeg2lib/Vlc.h
|
||||
IPU/mpeg2_vlc.h
|
||||
IPU/yuv2rgb.h
|
||||
)
|
||||
|
||||
@@ -919,14 +916,14 @@ set(pcsx2LinuxSources
|
||||
)
|
||||
|
||||
set(pcsx2OSXSources
|
||||
CDVD/Linux/DriveUtility.cpp
|
||||
CDVD/Linux/IOCtlSrc.cpp
|
||||
CDVD/Darwin/DriveUtility.cpp
|
||||
CDVD/Darwin/IOCtlSrc.cpp
|
||||
Darwin/DarwinFlatFileReader.cpp
|
||||
)
|
||||
|
||||
set(pcsx2FreeBSDSources
|
||||
CDVD/Linux/DriveUtility.cpp
|
||||
CDVD/Linux/IOCtlSrc.cpp
|
||||
CDVD/Darwin/DriveUtility.cpp
|
||||
CDVD/Darwin/IOCtlSrc.cpp
|
||||
Darwin/DarwinFlatFileReader.cpp
|
||||
)
|
||||
|
||||
@@ -990,10 +987,6 @@ set(pcsx2RecordingHeaders
|
||||
${rec_src}/Utilities/InputRecordingLogger.h
|
||||
)
|
||||
|
||||
# System headers
|
||||
set(pcsx2SystemHeaders
|
||||
System/RecTypes.h)
|
||||
|
||||
# Windows sources
|
||||
set(pcsx2WindowsSources
|
||||
CDVD/Windows/DriveUtility.cpp
|
||||
@@ -1119,7 +1112,6 @@ target_sources(PCSX2 PRIVATE
|
||||
${pcsx2FrontendHeaders}
|
||||
${pcsx2ps2Sources}
|
||||
${pcsx2ps2Headers}
|
||||
${pcsx2SystemHeaders}
|
||||
)
|
||||
|
||||
# platform sources
|
||||
|
||||
+23
-6
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -537,6 +537,8 @@ struct Pcsx2Config
|
||||
EnableEECache : 1;
|
||||
bool
|
||||
EnableFastmem : 1;
|
||||
bool
|
||||
PauseOnTLBMiss : 1;
|
||||
BITFIELD_END
|
||||
|
||||
RecompilerOptions();
|
||||
@@ -605,15 +607,18 @@ struct Pcsx2Config
|
||||
{
|
||||
static const char* AspectRatioNames[];
|
||||
static const char* FMVAspectRatioSwitchNames[];
|
||||
static const char* VideoCaptureContainers[];
|
||||
static const char* CaptureContainers[];
|
||||
|
||||
static const char* GetRendererName(GSRendererType type);
|
||||
|
||||
static constexpr float DEFAULT_FRAME_RATE_NTSC = 59.94f;
|
||||
static constexpr float DEFAULT_FRAME_RATE_PAL = 50.00f;
|
||||
|
||||
static constexpr u32 DEFAULT_VIDEO_CAPTURE_BITRATE = 6000;
|
||||
static const char* DEFAULT_VIDEO_CAPTURE_CONTAINER;
|
||||
static constexpr int DEFAULT_VIDEO_CAPTURE_BITRATE = 6000;
|
||||
static constexpr int DEFAULT_VIDEO_CAPTURE_WIDTH = 640;
|
||||
static constexpr int DEFAULT_VIDEO_CAPTURE_HEIGHT = 480;
|
||||
static constexpr int DEFAULT_AUDIO_CAPTURE_BITRATE = 160;
|
||||
static const char* DEFAULT_CAPTURE_CONTAINER;
|
||||
|
||||
union
|
||||
{
|
||||
@@ -679,7 +684,12 @@ struct Pcsx2Config
|
||||
DumpPaletteTextures : 1,
|
||||
LoadTextureReplacements : 1,
|
||||
LoadTextureReplacementsAsync : 1,
|
||||
PrecacheTextureReplacements : 1;
|
||||
PrecacheTextureReplacements : 1,
|
||||
EnableVideoCapture : 1,
|
||||
EnableVideoCaptureParameters : 1,
|
||||
VideoCaptureAutoResolution : 1,
|
||||
EnableAudioCapture : 1,
|
||||
EnableAudioCaptureParameters : 1;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -752,9 +762,15 @@ struct Pcsx2Config
|
||||
GSScreenshotFormat ScreenshotFormat{GSScreenshotFormat::PNG};
|
||||
int ScreenshotQuality{50};
|
||||
|
||||
std::string VideoCaptureContainer{DEFAULT_VIDEO_CAPTURE_CONTAINER};
|
||||
std::string CaptureContainer{DEFAULT_CAPTURE_CONTAINER};
|
||||
std::string VideoCaptureCodec;
|
||||
std::string VideoCaptureParameters;
|
||||
std::string AudioCaptureCodec;
|
||||
std::string AudioCaptureParameters;
|
||||
int VideoCaptureBitrate{DEFAULT_VIDEO_CAPTURE_BITRATE};
|
||||
int VideoCaptureWidth{DEFAULT_VIDEO_CAPTURE_WIDTH};
|
||||
int VideoCaptureHeight{DEFAULT_VIDEO_CAPTURE_HEIGHT};
|
||||
int AudioCaptureBitrate{DEFAULT_AUDIO_CAPTURE_BITRATE};
|
||||
|
||||
std::string Adapter;
|
||||
std::string HWDumpDirectory;
|
||||
@@ -1309,6 +1325,7 @@ namespace EmuFolders
|
||||
extern std::string GameSettings;
|
||||
extern std::string Textures;
|
||||
extern std::string InputProfiles;
|
||||
extern std::string Videos;
|
||||
|
||||
// Assumes that AppRoot and DataRoot have been initialized.
|
||||
void SetDefaults(SettingsInterface& si);
|
||||
|
||||
+7
-1
@@ -445,6 +445,10 @@ u32 UpdateVSyncRate()
|
||||
|
||||
if (vSyncInfo.Framerate != frames_per_second || vSyncInfo.VideoMode != gsVideoMode)
|
||||
{
|
||||
// NBA Jam 2004 PAL will fail to display 3D on the menu if this value isn't correct on reset.
|
||||
if (video_mode_initialized && vSyncInfo.VideoMode != gsVideoMode)
|
||||
CSRreg.FIELD = 1;
|
||||
|
||||
vSyncInfo.VideoMode = gsVideoMode;
|
||||
|
||||
vSyncInfoCalc(&vSyncInfo, frames_per_second, total_scanlines);
|
||||
@@ -457,7 +461,9 @@ u32 UpdateVSyncRate()
|
||||
|
||||
hsyncCounter.CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated
|
||||
vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated
|
||||
|
||||
hsyncCounter.sCycle = cpuRegs.cycle;
|
||||
vsyncCounter.sCycle = cpuRegs.cycle;
|
||||
vsyncCounter.Mode = MODE_VRENDER;
|
||||
cpuRcntSet();
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,6 @@ struct EECNT_MODE
|
||||
u32 OverflowReached:1;
|
||||
};
|
||||
|
||||
// fixme: Cycle and sCycleT members are unused.
|
||||
// But they can't be removed without making a new savestate version.
|
||||
struct Counter
|
||||
{
|
||||
u32 count;
|
||||
|
||||
+101
-60
@@ -15,21 +15,24 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <algorithm>
|
||||
#ifdef __POSIX__
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || (__APPLE__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include "common/Assertions.h"
|
||||
@@ -39,13 +42,14 @@
|
||||
|
||||
#include "AdapterUtils.h"
|
||||
|
||||
using namespace PacketReader;
|
||||
using namespace PacketReader::IP;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
bool AdapterUtils::GetAdapter(const std::string& name, Adapter* adapter, AdapterBuffer* buffer)
|
||||
{
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapterInfo;
|
||||
@@ -54,14 +58,14 @@ bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSE
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
adapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: GetWin32Adapter() buffer too small, resizing");
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
@@ -69,31 +73,32 @@ bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSE
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
adapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
pAdapterInfo = AdapterInfo.get();
|
||||
pAdapterInfo = adapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (strcmp(pAdapterInfo->AdapterName, name.c_str()) == 0)
|
||||
{
|
||||
*adapter = *pAdapterInfo;
|
||||
buffer->swap(AdapterInfo);
|
||||
buffer->swap(adapterInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
} while (pAdapterInfo);
|
||||
|
||||
return false;
|
||||
}
|
||||
bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
bool AdapterUtils::GetAdapterAuto(Adapter* adapter, AdapterBuffer* buffer)
|
||||
{
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapter;
|
||||
@@ -102,7 +107,7 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
adapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
@@ -110,7 +115,7 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
|
||||
DevCon.WriteLn("DEV9: PCAPGetWin32Adapter() buffer too small, resizing");
|
||||
//
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
@@ -118,45 +123,45 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
adapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return 0;
|
||||
|
||||
pAdapter = AdapterInfo.get();
|
||||
pAdapter = adapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK &&
|
||||
pAdapter->OperStatus == IfOperStatusUp)
|
||||
{
|
||||
//Search for an adapter with;
|
||||
//IPv4 Address
|
||||
//DNS
|
||||
//Gateway
|
||||
// Search for an adapter with;
|
||||
// IPv4 Address,
|
||||
// DNS,
|
||||
// Gateway.
|
||||
|
||||
bool hasIPv4 = false;
|
||||
bool hasDNS = false;
|
||||
bool hasGateway = false;
|
||||
|
||||
//IPv4
|
||||
// IPv4.
|
||||
if (GetAdapterIP(pAdapter).has_value())
|
||||
hasIPv4 = true;
|
||||
|
||||
//DNS
|
||||
// DNS.
|
||||
if (GetDNS(pAdapter).size() > 0)
|
||||
hasDNS = true;
|
||||
|
||||
//Gateway
|
||||
// Gateway.
|
||||
if (GetGateways(pAdapter).size() > 0)
|
||||
hasGateway = true;
|
||||
|
||||
if (hasIPv4 && hasDNS && hasGateway)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
buffer->swap(AdapterInfo);
|
||||
buffer->swap(adapterInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -167,16 +172,18 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
|
||||
return false;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
bool AdapterUtils::GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer)
|
||||
bool AdapterUtils::GetAdapter(const std::string& name, Adapter* adapter, AdapterBuffer* buffer)
|
||||
{
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* ifa;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
int error = getifaddrs(&ifa);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
std::unique_ptr<ifaddrs, IfAdaptersDeleter> adapterInfo(ifa, IfAdaptersDeleter());
|
||||
|
||||
pAdapter = adapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
@@ -189,32 +196,33 @@ bool AdapterUtils::GetIfAdapter(const std::string& name, ifaddrs* adapter, ifadd
|
||||
if (pAdapter != nullptr)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
buffer->swap(adapterInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
|
||||
bool AdapterUtils::GetAdapterAuto(Adapter* adapter, AdapterBuffer* buffer)
|
||||
{
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* ifa;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
int error = getifaddrs(&ifa);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
std::unique_ptr<ifaddrs, IfAdaptersDeleter> adapterInfo(ifa, IfAdaptersDeleter());
|
||||
|
||||
pAdapter = adapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if ((pAdapter->ifa_flags & IFF_LOOPBACK) == 0 &&
|
||||
(pAdapter->ifa_flags & IFF_UP) != 0)
|
||||
{
|
||||
//Search for an adapter with;
|
||||
//IPv4 Address
|
||||
//Gateway
|
||||
// Search for an adapter with;
|
||||
// IPv4 Address,
|
||||
// Gateway.
|
||||
|
||||
bool hasIPv4 = false;
|
||||
bool hasGateway = false;
|
||||
@@ -228,7 +236,7 @@ bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
|
||||
if (hasIPv4 && hasGateway)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
buffer->swap(adapterInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -236,14 +244,47 @@ bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
} while (pAdapter);
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//AdapterIP
|
||||
// AdapterMAC.
|
||||
#ifdef _WIN32
|
||||
std::optional<IP_Address> AdapterUtils::GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter)
|
||||
std::optional<MAC_Address> AdapterUtils::GetAdapterMAC(Adapter* adapter)
|
||||
{
|
||||
if (adapter != nullptr && adapter->PhysicalAddressLength == 6)
|
||||
return *(MAC_Address*)adapter->PhysicalAddress;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
#ifdef __linux__
|
||||
std::optional<MAC_Address> AdapterUtils::GetAdapterMAC(Adapter* adapter)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
strcpy(ifr.ifr_name, adapter->ifa_name);
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
int ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
|
||||
close(fd);
|
||||
|
||||
if (ret == 0)
|
||||
return *(MAC_Address*)ifr.ifr_hwaddr.sa_data;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
#else
|
||||
std::optional<MAC_Address> AdapterUtils::GetAdapterMAC(Adapter* adapter)
|
||||
{
|
||||
Console.Error("DEV9: Unsupported OS, can't get MAC address");
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// AdapterIP.
|
||||
#ifdef _WIN32
|
||||
std::optional<IP_Address> AdapterUtils::GetAdapterIP(Adapter* adapter)
|
||||
{
|
||||
PIP_ADAPTER_UNICAST_ADDRESS address = nullptr;
|
||||
if (adapter != nullptr)
|
||||
@@ -261,7 +302,7 @@ std::optional<IP_Address> AdapterUtils::GetAdapterIP(PIP_ADAPTER_ADDRESSES adapt
|
||||
return std::nullopt;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
std::optional<IP_Address> AdapterUtils::GetAdapterIP(ifaddrs* adapter)
|
||||
std::optional<IP_Address> AdapterUtils::GetAdapterIP(Adapter* adapter)
|
||||
{
|
||||
sockaddr* address = nullptr;
|
||||
if (adapter != nullptr)
|
||||
@@ -279,9 +320,9 @@ std::optional<IP_Address> AdapterUtils::GetAdapterIP(ifaddrs* adapter)
|
||||
}
|
||||
#endif
|
||||
|
||||
//Gateways
|
||||
// Gateways.
|
||||
#ifdef _WIN32
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(PIP_ADAPTER_ADDRESSES adapter)
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
|
||||
{
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
@@ -303,10 +344,10 @@ std::vector<IP_Address> AdapterUtils::GetGateways(PIP_ADAPTER_ADDRESSES adapter)
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
#ifdef __linux__
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
|
||||
{
|
||||
///proc/net/route contains some information about gateway addresses,
|
||||
//and separates the information about by each interface.
|
||||
// /proc/net/route contains some information about gateway addresses,
|
||||
// and separates the information about by each interface.
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
@@ -325,8 +366,8 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
routeLines.push_back(line);
|
||||
route.close();
|
||||
|
||||
//Columns are as follows (first-line header):
|
||||
//Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
// Columns are as follows (first-line header):
|
||||
// Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT.
|
||||
for (size_t i = 1; i < routeLines.size(); i++)
|
||||
{
|
||||
std::string line = routeLines[i];
|
||||
@@ -349,14 +390,14 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
return collection;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || (__APPLE__)
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
|
||||
{
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
//Get index for our adapter by matching the adapter name
|
||||
// Get index for our adapter by matching the adapter name.
|
||||
int ifIndex = -1;
|
||||
|
||||
struct if_nameindex* ifNI;
|
||||
@@ -379,14 +420,14 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
}
|
||||
if_freenameindex(ifNI);
|
||||
|
||||
//Check if we found the adapter
|
||||
// Check if we found the adapter.
|
||||
if (ifIndex == -1)
|
||||
{
|
||||
Console.Error("DEV9: Failed to get index for adapter");
|
||||
return collection;
|
||||
}
|
||||
|
||||
//Find the gateway by looking though the routing information
|
||||
// Find the gateway by looking though the routing information.
|
||||
int name[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
|
||||
size_t bufferLen = 0;
|
||||
|
||||
@@ -396,7 +437,7 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
return collection;
|
||||
}
|
||||
|
||||
//len is an estimate, double it to be safe
|
||||
// bufferLen is an estimate, double it to be safe.
|
||||
bufferLen *= 2;
|
||||
std::unique_ptr<u8[]> buffer = std::make_unique<u8[]>(bufferLen);
|
||||
|
||||
@@ -416,7 +457,7 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
sockaddr* sockaddrs = (sockaddr*)(hdr + 1);
|
||||
pxAssert(sockaddrs[RTAX_DST].sa_family == AF_INET);
|
||||
|
||||
//Default gateway has no destination address
|
||||
// Default gateway has no destination address.
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)&sockaddrs[RTAX_DST];
|
||||
if (sockaddr->sin_addr.s_addr != 0)
|
||||
continue;
|
||||
@@ -429,7 +470,7 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
return collection;
|
||||
}
|
||||
#else
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
|
||||
{
|
||||
Console.Error("DEV9: Unsupported OS, can't find Gateway");
|
||||
return {};
|
||||
@@ -437,9 +478,9 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//DNS
|
||||
// DNS.
|
||||
#ifdef _WIN32
|
||||
std::vector<IP_Address> AdapterUtils::GetDNS(PIP_ADAPTER_ADDRESSES adapter)
|
||||
std::vector<IP_Address> AdapterUtils::GetDNS(Adapter* adapter)
|
||||
{
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
@@ -460,9 +501,9 @@ std::vector<IP_Address> AdapterUtils::GetDNS(PIP_ADAPTER_ADDRESSES adapter)
|
||||
return collection;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
std::vector<IP_Address> AdapterUtils::GetDNS(ifaddrs* adapter)
|
||||
std::vector<IP_Address> AdapterUtils::GetDNS(Adapter* adapter)
|
||||
{
|
||||
//On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore adapter
|
||||
// On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore the adapter parameter.
|
||||
|
||||
// Parse /etc/resolv.conf for all of the "nameserver" entries.
|
||||
// These are the DNS servers the machine is configured to use.
|
||||
|
||||
+17
-14
@@ -26,25 +26,28 @@
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "DEV9/PacketReader/MAC_Address.h"
|
||||
#include "DEV9/PacketReader/IP/IP_Address.h"
|
||||
|
||||
namespace AdapterUtils
|
||||
{
|
||||
#ifdef _WIN32
|
||||
bool GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
|
||||
bool GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
|
||||
|
||||
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter);
|
||||
//Mask
|
||||
std::vector<PacketReader::IP::IP_Address> GetGateways(PIP_ADAPTER_ADDRESSES adapter);
|
||||
std::vector<PacketReader::IP::IP_Address> GetDNS(PIP_ADAPTER_ADDRESSES adapter);
|
||||
typedef IP_ADAPTER_ADDRESSES Adapter;
|
||||
typedef std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterBuffer;
|
||||
#elif defined(__POSIX__)
|
||||
bool GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer);
|
||||
bool GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer);
|
||||
|
||||
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(ifaddrs* adapter);
|
||||
//Mask
|
||||
std::vector<PacketReader::IP::IP_Address> GetGateways(ifaddrs* adapter);
|
||||
std::vector<PacketReader::IP::IP_Address> GetDNS(ifaddrs* adapter);
|
||||
typedef ifaddrs Adapter;
|
||||
struct IfAdaptersDeleter
|
||||
{
|
||||
void operator()(ifaddrs* buffer) const { freeifaddrs(buffer); }
|
||||
};
|
||||
typedef std::unique_ptr<ifaddrs, IfAdaptersDeleter> AdapterBuffer;
|
||||
#endif
|
||||
bool GetAdapter(const std::string& name, Adapter* adapter, AdapterBuffer* buffer);
|
||||
bool GetAdapterAuto(Adapter* adapter, AdapterBuffer* buffer);
|
||||
|
||||
std::optional<PacketReader::MAC_Address> GetAdapterMAC(Adapter* adapter);
|
||||
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(Adapter* adapter);
|
||||
// Mask.
|
||||
std::vector<PacketReader::IP::IP_Address> GetGateways(Adapter* adapter);
|
||||
std::vector<PacketReader::IP::IP_Address> GetDNS(Adapter* adapter);
|
||||
}; // namespace AdapterUtils
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "ARP_PacketEditor.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winsock.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace PacketReader::ARP
|
||||
{
|
||||
ARP_PacketEditor::ARP_PacketEditor(PayloadPtr* pkt)
|
||||
: basePkt{pkt}
|
||||
{
|
||||
}
|
||||
|
||||
u16 ARP_PacketEditor::GetHardwareType()
|
||||
{
|
||||
return ntohs(*(u16*)&basePkt->data[0]);
|
||||
}
|
||||
|
||||
u16 ARP_PacketEditor::GetProtocol()
|
||||
{
|
||||
return ntohs(*(u16*)&basePkt->data[2]);
|
||||
}
|
||||
|
||||
u8 ARP_PacketEditor::GetHardwareAddressLength()
|
||||
{
|
||||
return basePkt->data[4];
|
||||
}
|
||||
u8 ARP_PacketEditor::GetProtocolAddressLength()
|
||||
{
|
||||
return basePkt->data[5];
|
||||
}
|
||||
|
||||
u16 ARP_PacketEditor::GetOp()
|
||||
{
|
||||
return ntohs(*(u16*)&basePkt->data[6]);
|
||||
}
|
||||
|
||||
u8* ARP_PacketEditor::SenderHardwareAddress()
|
||||
{
|
||||
return &basePkt->data[8];
|
||||
}
|
||||
|
||||
u8* ARP_PacketEditor::SenderProtocolAddress()
|
||||
{
|
||||
int offset = 8 + GetHardwareAddressLength();
|
||||
return &basePkt->data[offset];
|
||||
}
|
||||
|
||||
u8* ARP_PacketEditor::TargetHardwareAddress()
|
||||
{
|
||||
int offset = 8 + GetHardwareAddressLength() + GetProtocolAddressLength();
|
||||
return &basePkt->data[offset];
|
||||
}
|
||||
|
||||
u8* ARP_PacketEditor::TargetProtocolAddress()
|
||||
{
|
||||
int offset = 8 + 2 * GetHardwareAddressLength() + GetProtocolAddressLength();
|
||||
return &basePkt->data[offset];
|
||||
}
|
||||
} // namespace PacketReader::ARP
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -15,17 +15,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
class GSCodeBuffer
|
||||
#include "DEV9/PacketReader/Payload.h"
|
||||
|
||||
namespace PacketReader::ARP
|
||||
{
|
||||
std::vector<void*> m_buffers;
|
||||
size_t m_blocksize;
|
||||
size_t m_pos, m_reserved;
|
||||
u8* m_ptr;
|
||||
class ARP_PacketEditor
|
||||
{
|
||||
private:
|
||||
PayloadPtr* basePkt;
|
||||
|
||||
public:
|
||||
GSCodeBuffer(size_t blocksize = 4096 * 64); // 256k
|
||||
virtual ~GSCodeBuffer();
|
||||
public:
|
||||
|
||||
void* GetBuffer(size_t size);
|
||||
void ReleaseBuffer(size_t size);
|
||||
};
|
||||
ARP_PacketEditor(PayloadPtr* pkt);
|
||||
|
||||
u16 GetHardwareType();
|
||||
u16 GetProtocol();
|
||||
u8 GetHardwareAddressLength();
|
||||
u8 GetProtocolAddressLength();
|
||||
u16 GetOp();
|
||||
|
||||
u8* SenderHardwareAddress();
|
||||
u8* SenderProtocolAddress();
|
||||
u8* TargetHardwareAddress();
|
||||
u8* TargetProtocolAddress();
|
||||
};
|
||||
} // namespace PacketReader::ARP
|
||||
@@ -27,8 +27,8 @@ namespace PacketReader
|
||||
EthernetFrame::EthernetFrame(NetPacket* pkt)
|
||||
{
|
||||
int offset = 0;
|
||||
NetLib::ReadByteArray((u8*)pkt->buffer, &offset, 6, destinationMAC);
|
||||
NetLib::ReadByteArray((u8*)pkt->buffer, &offset, 6, sourceMAC);
|
||||
NetLib::ReadMACAddress((u8*)pkt->buffer, &offset, &destinationMAC);
|
||||
NetLib::ReadMACAddress((u8*)pkt->buffer, &offset, &sourceMAC);
|
||||
|
||||
headerLength = 14; //(6+6+2)
|
||||
|
||||
@@ -51,8 +51,8 @@ namespace PacketReader
|
||||
int counter = 0;
|
||||
|
||||
pkt->size = headerLength + payload->GetLength();
|
||||
NetLib::WriteByteArray((u8*)pkt->buffer, &counter, 6, destinationMAC);
|
||||
NetLib::WriteByteArray((u8*)pkt->buffer, &counter, 6, sourceMAC);
|
||||
NetLib::WriteMACAddress((u8*)pkt->buffer, &counter, destinationMAC);
|
||||
NetLib::WriteMACAddress((u8*)pkt->buffer, &counter, sourceMAC);
|
||||
//
|
||||
NetLib::WriteUInt16((u8*)pkt->buffer, &counter, protocol);
|
||||
//
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "DEV9/net.h"
|
||||
#include "MAC_Address.h"
|
||||
#include "Payload.h"
|
||||
|
||||
namespace PacketReader
|
||||
@@ -34,8 +35,8 @@ namespace PacketReader
|
||||
class EthernetFrame
|
||||
{
|
||||
public:
|
||||
u8 destinationMAC[6] = {0};
|
||||
u8 sourceMAC[6] = {0};
|
||||
MAC_Address destinationMAC{};
|
||||
MAC_Address sourceMAC{};
|
||||
|
||||
u16 protocol = 0;
|
||||
int headerLength = 14;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "EthernetFrameEditor.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winsock.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace PacketReader
|
||||
{
|
||||
EthernetFrameEditor::EthernetFrameEditor(NetPacket* pkt)
|
||||
: basePkt{pkt}
|
||||
{
|
||||
headerLength = 14; //(6+6+2)
|
||||
|
||||
//Note: we don't have to worry about the Ethernet Frame CRC as it is not included in the packet
|
||||
//Note: We don't support tagged frames
|
||||
|
||||
payload = std::make_unique<PayloadPtr>((u8*)&basePkt->buffer[14], pkt->size - headerLength);
|
||||
}
|
||||
|
||||
MAC_Address EthernetFrameEditor::GetDestinationMAC()
|
||||
{
|
||||
return *(MAC_Address*)&basePkt->buffer[0];
|
||||
}
|
||||
void EthernetFrameEditor::SetDestinationMAC(MAC_Address value)
|
||||
{
|
||||
*(MAC_Address*)&basePkt->buffer[0] = value;
|
||||
}
|
||||
|
||||
MAC_Address EthernetFrameEditor::GetSourceMAC()
|
||||
{
|
||||
return *(MAC_Address*)&basePkt->buffer[6];
|
||||
}
|
||||
void EthernetFrameEditor::SetSourceMAC(MAC_Address value)
|
||||
{
|
||||
*(MAC_Address*)&basePkt->buffer[6] = value;
|
||||
}
|
||||
|
||||
u16 EthernetFrameEditor::GetProtocol()
|
||||
{
|
||||
return ntohs(*(u16*)&basePkt->buffer[12]);
|
||||
}
|
||||
|
||||
PayloadPtr* EthernetFrameEditor::GetPayload()
|
||||
{
|
||||
return payload.get();
|
||||
}
|
||||
} // namespace PacketReader
|
||||
@@ -0,0 +1,45 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DEV9/net.h"
|
||||
#include "MAC_Address.h"
|
||||
#include "Payload.h"
|
||||
|
||||
namespace PacketReader
|
||||
{
|
||||
class EthernetFrameEditor
|
||||
{
|
||||
public:
|
||||
int headerLength = 14;
|
||||
//Length
|
||||
private:
|
||||
NetPacket* basePkt;
|
||||
std::unique_ptr<PayloadPtr> payload;
|
||||
|
||||
public:
|
||||
EthernetFrameEditor(NetPacket* pkt);
|
||||
|
||||
MAC_Address GetDestinationMAC();
|
||||
void SetDestinationMAC(MAC_Address value);
|
||||
MAC_Address GetSourceMAC();
|
||||
void SetSourceMAC(MAC_Address value);
|
||||
|
||||
u16 GetProtocol();
|
||||
|
||||
PayloadPtr* GetPayload();
|
||||
};
|
||||
} // namespace PacketReader
|
||||
@@ -107,9 +107,9 @@ namespace PacketReader::IP
|
||||
NetLib::ReadUInt16(buffer, &offset, &checksum);
|
||||
|
||||
//Bits 96-127
|
||||
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&sourceIP);
|
||||
NetLib::ReadIPAddress(buffer, &offset, &sourceIP);
|
||||
//Bits 128-159
|
||||
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&destinationIP);
|
||||
NetLib::ReadIPAddress(buffer, &offset, &destinationIP);
|
||||
|
||||
//Bits 160+
|
||||
if (headerLength > 20) //IP options (if any)
|
||||
@@ -194,8 +194,8 @@ namespace PacketReader::IP
|
||||
NetLib::WriteByte08(buffer, offset, protocol);
|
||||
NetLib::WriteUInt16(buffer, offset, checksum); //header csum
|
||||
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&sourceIP);
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&destinationIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, sourceIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, destinationIP);
|
||||
|
||||
//options
|
||||
for (size_t i = 0; i < options.size(); i++)
|
||||
@@ -243,8 +243,8 @@ namespace PacketReader::IP
|
||||
NetLib::WriteByte08(headerSegment, &counter, protocol);
|
||||
NetLib::WriteUInt16(headerSegment, &counter, 0); //header csum
|
||||
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&sourceIP);
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&destinationIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, sourceIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, destinationIP);
|
||||
|
||||
//options
|
||||
for (size_t i = 0; i < options.size(); i++)
|
||||
@@ -276,8 +276,8 @@ namespace PacketReader::IP
|
||||
NetLib::WriteByte08(headerSegment, &counter, protocol);
|
||||
NetLib::WriteUInt16(headerSegment, &counter, checksum); //header csum
|
||||
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&sourceIP);
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&destinationIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, sourceIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, destinationIP);
|
||||
|
||||
//options
|
||||
for (size_t i = 0; i < options.size(); i++)
|
||||
|
||||
@@ -263,8 +263,8 @@ namespace PacketReader::IP::TCP
|
||||
u8* headerSegment = new u8[pHeaderLen];
|
||||
int counter = 0;
|
||||
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
|
||||
NetLib::WriteByte08(headerSegment, &counter, 0);
|
||||
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
|
||||
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
|
||||
@@ -291,8 +291,8 @@ namespace PacketReader::IP::TCP
|
||||
u8* headerSegment = new u8[pHeaderLen];
|
||||
int counter = 0;
|
||||
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
|
||||
NetLib::WriteByte08(headerSegment, &counter, 0);
|
||||
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
|
||||
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace PacketReader::IP::UDP::DHCP
|
||||
DHCPopSubnet::DHCPopSubnet(u8* data, int offset)
|
||||
{
|
||||
offset += 2;
|
||||
NetLib::ReadByteArray(data, &offset, 4, (u8*)&subnetMask);
|
||||
NetLib::ReadIPAddress(data, &offset, &subnetMask);
|
||||
}
|
||||
void DHCPopSubnet::WriteBytes(u8* buffer, int* offset)
|
||||
{
|
||||
NetLib::WriteByte08(buffer, offset, GetCode());
|
||||
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&subnetMask);
|
||||
NetLib::WriteIPAddress(buffer, offset, subnetMask);
|
||||
}
|
||||
|
||||
DHCPopRouter::DHCPopRouter(const std::vector<IP_Address>& routerIPs)
|
||||
@@ -137,14 +137,14 @@ namespace PacketReader::IP::UDP::DHCP
|
||||
DHCPopBCIP::DHCPopBCIP(u8* data, int offset)
|
||||
{
|
||||
offset += 2;
|
||||
NetLib::ReadByteArray(data, &offset, 4, (u8*)&broadcastIP);
|
||||
NetLib::ReadIPAddress(data, &offset, &broadcastIP);
|
||||
}
|
||||
void DHCPopBCIP::WriteBytes(u8* buffer, int* offset)
|
||||
{
|
||||
NetLib::WriteByte08(buffer, offset, GetCode());
|
||||
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
|
||||
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&broadcastIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, broadcastIP);
|
||||
}
|
||||
|
||||
bool DHCPopNBIOSType::GetHNode()
|
||||
@@ -228,14 +228,14 @@ namespace PacketReader::IP::UDP::DHCP
|
||||
DHCPopREQIP::DHCPopREQIP(u8* data, int offset)
|
||||
{
|
||||
offset += 2;
|
||||
NetLib::ReadByteArray(data, &offset, 4, (u8*)&requestedIP);
|
||||
NetLib::ReadIPAddress(data, &offset, &requestedIP);
|
||||
}
|
||||
void DHCPopREQIP::WriteBytes(u8* buffer, int* offset)
|
||||
{
|
||||
NetLib::WriteByte08(buffer, offset, GetCode());
|
||||
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
|
||||
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&requestedIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, requestedIP);
|
||||
}
|
||||
|
||||
DHCPopIPLT::DHCPopIPLT(u32 LeaseTime)
|
||||
@@ -279,14 +279,14 @@ namespace PacketReader::IP::UDP::DHCP
|
||||
DHCPopSERVIP::DHCPopSERVIP(u8* data, int offset)
|
||||
{
|
||||
offset += 2;
|
||||
NetLib::ReadByteArray(data, &offset, 4, (u8*)&serverIP);
|
||||
NetLib::ReadIPAddress(data, &offset, &serverIP);
|
||||
}
|
||||
void DHCPopSERVIP::WriteBytes(u8* buffer, int* offset)
|
||||
{
|
||||
NetLib::WriteByte08(buffer, offset, GetCode());
|
||||
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
|
||||
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&serverIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, serverIP);
|
||||
}
|
||||
|
||||
DHCPopREQLIST::DHCPopREQLIST(const std::vector<u8>& requestList)
|
||||
|
||||
@@ -36,16 +36,16 @@ namespace PacketReader::IP::UDP::DHCP
|
||||
NetLib::ReadUInt16(buffer, &offset, &flags);
|
||||
|
||||
//Bits 96-127 //Bytes 12-15
|
||||
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&clientIP);
|
||||
NetLib::ReadIPAddress(buffer, &offset, &clientIP);
|
||||
|
||||
//Bits 128-159 //Bytes 16-19
|
||||
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&yourIP);
|
||||
NetLib::ReadIPAddress(buffer, &offset, &yourIP);
|
||||
|
||||
//Bits 160-191 //Bytes 20-23
|
||||
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&serverIP);
|
||||
NetLib::ReadIPAddress(buffer, &offset, &serverIP);
|
||||
|
||||
//Bits 192-223 //Bytes 24-27
|
||||
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&gatewayIP);
|
||||
NetLib::ReadIPAddress(buffer, &offset, &gatewayIP);
|
||||
|
||||
//Bits 192+ //Bytes 28-43
|
||||
NetLib::ReadByteArray(buffer, &offset, 16, clientHardwareAddress);
|
||||
@@ -194,10 +194,10 @@ namespace PacketReader::IP::UDP::DHCP
|
||||
NetLib::WriteUInt16(buffer, offset, seconds);
|
||||
NetLib::WriteUInt16(buffer, offset, flags);
|
||||
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&clientIP);
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&yourIP);
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&serverIP);
|
||||
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&gatewayIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, clientIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, yourIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, serverIP);
|
||||
NetLib::WriteIPAddress(buffer, offset, gatewayIP);
|
||||
|
||||
NetLib::WriteByteArray(buffer, offset, 16, clientHardwareAddress);
|
||||
//empty bytes
|
||||
|
||||
@@ -93,8 +93,8 @@ namespace PacketReader::IP::UDP
|
||||
u8* headerSegment = new u8[pHeaderLen];
|
||||
int counter = 0;
|
||||
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
|
||||
NetLib::WriteByte08(headerSegment, &counter, 0);
|
||||
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
|
||||
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
|
||||
@@ -120,8 +120,8 @@ namespace PacketReader::IP::UDP
|
||||
u8* headerSegment = new u8[pHeaderLen];
|
||||
int counter = 0;
|
||||
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
|
||||
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
|
||||
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
|
||||
NetLib::WriteByte08(headerSegment, &counter, 0);
|
||||
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
|
||||
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -15,8 +15,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
//#define ENABLE_VTUNE
|
||||
namespace PacketReader
|
||||
{
|
||||
#pragma pack(push, 1)
|
||||
struct MAC_Address
|
||||
{
|
||||
union
|
||||
{
|
||||
u8 bytes[6];
|
||||
struct
|
||||
{
|
||||
u32 integer03;
|
||||
u16 short45;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define ENABLE_JIT_RASTERIZER
|
||||
|
||||
//#define DISABLE_HW_TEXTURE_CACHE // Slow but fixes a lot of bugs
|
||||
bool operator==(const MAC_Address& other) const { return (this->u.integer03 == other.u.integer03) && (this->u.short45 == other.u.short45); }
|
||||
bool operator!=(const MAC_Address& other) const { return (this->u.integer03 != other.u.integer03) || (this->u.short45 != other.u.short45); }
|
||||
};
|
||||
#pragma pack(pop)
|
||||
} // namespace PacketReader
|
||||
@@ -1,75 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "NetLib.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winsock.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace PacketReader::NetLib
|
||||
{
|
||||
void WriteByte08(u8* data, int* index, u8 value)
|
||||
{
|
||||
data[*index] = value;
|
||||
*index += sizeof(u8);
|
||||
}
|
||||
void WriteUInt16(u8* data, int* index, u16 value)
|
||||
{
|
||||
*(u16*)&data[*index] = htons(value);
|
||||
*index += sizeof(u16);
|
||||
}
|
||||
void WriteUInt32(u8* data, int* index, u32 value)
|
||||
{
|
||||
*(u32*)&data[*index] = htonl(value);
|
||||
*index += sizeof(u32);
|
||||
}
|
||||
|
||||
//Special
|
||||
void WriteByteArray(u8* data, int* index, int length, u8* value)
|
||||
{
|
||||
memcpy(&data[*index], value, length);
|
||||
*index += length;
|
||||
}
|
||||
|
||||
|
||||
//Read
|
||||
void ReadByte08(u8* data, int* index, u8* value)
|
||||
{
|
||||
*value = data[*index];
|
||||
*index += sizeof(u8);
|
||||
}
|
||||
void ReadUInt16(u8* data, int* index, u16* value)
|
||||
{
|
||||
*value = ntohs(*(u16*)&data[*index]);
|
||||
*index += sizeof(u16);
|
||||
}
|
||||
void ReadUInt32(u8* data, int* index, u32* value)
|
||||
{
|
||||
*value = ntohl(*(u32*)&data[*index]);
|
||||
*index += sizeof(u32);
|
||||
}
|
||||
|
||||
//Special
|
||||
void ReadByteArray(u8* data, int* index, int length, u8* value)
|
||||
{
|
||||
memcpy(value, &data[*index], length);
|
||||
*index += length;
|
||||
}
|
||||
} // namespace PacketReader::NetLib
|
||||
@@ -15,17 +15,82 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DEV9/PacketReader/MAC_Address.h"
|
||||
#include "DEV9/PacketReader/IP/IP_Address.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winsock.h"
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace PacketReader::NetLib
|
||||
{
|
||||
void WriteByte08(u8* data, int* index, u8 value);
|
||||
void WriteUInt16(u8* data, int* index, u16 value);
|
||||
void WriteUInt32(u8* data, int* index, u32 value);
|
||||
// Write.
|
||||
inline void WriteByte08(u8* data, int* index, u8 value)
|
||||
{
|
||||
data[*index] = value;
|
||||
*index += sizeof(u8);
|
||||
}
|
||||
inline void WriteUInt16(u8* data, int* index, u16 value)
|
||||
{
|
||||
*(u16*)&data[*index] = htons(value);
|
||||
*index += sizeof(u16);
|
||||
}
|
||||
inline void WriteUInt32(u8* data, int* index, u32 value)
|
||||
{
|
||||
*(u32*)&data[*index] = htonl(value);
|
||||
*index += sizeof(u32);
|
||||
}
|
||||
|
||||
void WriteByteArray(u8* data, int* index, int length, u8* value);
|
||||
// Special write.
|
||||
inline void WriteMACAddress(u8* data, int* index, PacketReader::MAC_Address value)
|
||||
{
|
||||
*(PacketReader::MAC_Address*)&data[*index] = value;
|
||||
*index += sizeof(PacketReader::MAC_Address);
|
||||
}
|
||||
inline void WriteIPAddress(u8* data, int* index, PacketReader::IP::IP_Address value)
|
||||
{
|
||||
*(PacketReader::IP::IP_Address*)&data[*index] = value;
|
||||
*index += sizeof(PacketReader::IP::IP_Address);
|
||||
}
|
||||
inline void WriteByteArray(u8* data, int* index, int length, u8* value)
|
||||
{
|
||||
memcpy(&data[*index], value, length);
|
||||
*index += length;
|
||||
}
|
||||
|
||||
void ReadByte08(u8* data, int* index, u8* value);
|
||||
void ReadUInt16(u8* data, int* index, u16* value);
|
||||
void ReadUInt32(u8* data, int* index, u32* value);
|
||||
// Read.
|
||||
inline void ReadByte08(u8* data, int* index, u8* value)
|
||||
{
|
||||
*value = data[*index];
|
||||
*index += sizeof(u8);
|
||||
}
|
||||
inline void ReadUInt16(u8* data, int* index, u16* value)
|
||||
{
|
||||
*value = ntohs(*(u16*)&data[*index]);
|
||||
*index += sizeof(u16);
|
||||
}
|
||||
inline void ReadUInt32(u8* data, int* index, u32* value)
|
||||
{
|
||||
*value = ntohl(*(u32*)&data[*index]);
|
||||
*index += sizeof(u32);
|
||||
}
|
||||
|
||||
void ReadByteArray(u8* data, int* index, int length, u8* value);
|
||||
// Special read.
|
||||
inline void ReadMACAddress(u8* data, int* index, PacketReader::MAC_Address* value)
|
||||
{
|
||||
*value = *(PacketReader::MAC_Address*)&data[*index];
|
||||
*index += sizeof(PacketReader::MAC_Address);
|
||||
}
|
||||
inline void ReadIPAddress(u8* data, int* index, PacketReader::IP::IP_Address* value)
|
||||
{
|
||||
*value = *(PacketReader::IP::IP_Address*)&data[*index];
|
||||
*index += sizeof(PacketReader::IP::IP_Address);
|
||||
}
|
||||
inline void ReadByteArray(u8* data, int* index, int length, u8* value)
|
||||
{
|
||||
memcpy(value, &data[*index], length);
|
||||
*index += length;
|
||||
}
|
||||
} // namespace PacketReader::NetLib
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace Sessions
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
DevCon.WriteLn("DEV9: TCP: [SRV]Sending %d bytes", recived);
|
||||
DevCon.WriteLn("DEV9: TCP: [SRV] Sending %d bytes", recived);
|
||||
|
||||
PayloadData* recivedData = new PayloadData(recived);
|
||||
memcpy(recivedData->data.get(), buffer.get(), recived);
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace Sessions
|
||||
if (ret == SOCKET_ERROR)
|
||||
{
|
||||
hasData = false;
|
||||
Console.WriteLn("DEV9: UDP: select failed. Error Code: %d",
|
||||
Console.Error("DEV9: UDP: select failed. Error Code: %d",
|
||||
#ifdef _WIN32
|
||||
WSAGetLastError());
|
||||
#elif defined(__POSIX__)
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <wil/com.h>
|
||||
#include <wil/resource.h>
|
||||
|
||||
#include "DEV9/PacketReader/MAC_Address.h"
|
||||
|
||||
//=============
|
||||
// TAP IOCTLs
|
||||
//=============
|
||||
@@ -206,7 +208,7 @@ AdapterOptions TAPAdapter::GetAdapterOptions()
|
||||
return AdapterOptions::None;
|
||||
}
|
||||
|
||||
static int TAPGetMACAddress(HANDLE handle, u8* addr)
|
||||
static int TAPGetMACAddress(HANDLE handle, PacketReader::MAC_Address* addr)
|
||||
{
|
||||
DWORD len = 0;
|
||||
|
||||
@@ -551,17 +553,17 @@ TAPAdapter::TAPAdapter()
|
||||
|
||||
cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
u8 hostMAC[6];
|
||||
u8 newMAC[6];
|
||||
PacketReader::MAC_Address hostMAC;
|
||||
PacketReader::MAC_Address newMAC;
|
||||
|
||||
TAPGetMACAddress(htap, hostMAC);
|
||||
memcpy(newMAC, ps2MAC, 6);
|
||||
TAPGetMACAddress(htap, &hostMAC);
|
||||
newMAC = ps2MAC;
|
||||
|
||||
//Lets take the hosts last 2 bytes to make it unique on Xlink
|
||||
newMAC[5] = hostMAC[4];
|
||||
newMAC[4] = hostMAC[5];
|
||||
newMAC.bytes[5] = hostMAC.bytes[4];
|
||||
newMAC.bytes[4] = hostMAC.bytes[5];
|
||||
|
||||
SetMACAddress(newMAC);
|
||||
SetMACAddress(&newMAC);
|
||||
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
+12
-13
@@ -178,8 +178,8 @@ using namespace PacketReader::IP;
|
||||
using namespace PacketReader::IP::UDP;
|
||||
|
||||
const IP_Address NetAdapter::internalIP{{{192, 0, 2, 1}}};
|
||||
const u8 NetAdapter::broadcastMAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
const u8 NetAdapter::internalMAC[6] = {0x76, 0x6D, 0xF4, 0x63, 0x30, 0x31};
|
||||
const MAC_Address NetAdapter::broadcastMAC{{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}};
|
||||
const MAC_Address NetAdapter::internalMAC{{{0x76, 0x6D, 0xF4, 0x63, 0x30, 0x31}}};
|
||||
|
||||
NetAdapter::NetAdapter()
|
||||
{
|
||||
@@ -268,15 +268,14 @@ void NetAdapter::InspectRecv(NetPacket* pkt)
|
||||
}
|
||||
}
|
||||
|
||||
void NetAdapter::SetMACAddress(u8* mac)
|
||||
void NetAdapter::SetMACAddress(MAC_Address* mac)
|
||||
{
|
||||
if (mac == nullptr)
|
||||
memcpy(ps2MAC, defaultMAC, 6);
|
||||
ps2MAC = defaultMAC;
|
||||
else
|
||||
memcpy(ps2MAC, mac, 6);
|
||||
ps2MAC = *mac;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
dev9.eeprom[i] = ((u16*)ps2MAC)[i];
|
||||
*(MAC_Address*)&dev9.eeprom[0] = ps2MAC;
|
||||
|
||||
//The checksum seems to be all the values of the mac added up in 16bit chunks
|
||||
dev9.eeprom[3] = (dev9.eeprom[0] + dev9.eeprom[1] + dev9.eeprom[2]) & 0xffff;
|
||||
@@ -284,13 +283,13 @@ void NetAdapter::SetMACAddress(u8* mac)
|
||||
|
||||
bool NetAdapter::VerifyPkt(NetPacket* pkt, int read_size)
|
||||
{
|
||||
if ((memcmp(pkt->buffer, ps2MAC, 6) != 0) && (memcmp(pkt->buffer, &broadcastMAC, 6) != 0))
|
||||
if ((*(MAC_Address*)&pkt->buffer[0] != ps2MAC) && (*(MAC_Address*)&pkt->buffer[0] != broadcastMAC))
|
||||
{
|
||||
//ignore strange packets
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(pkt->buffer + 6, ps2MAC, 6) == 0)
|
||||
if (*(MAC_Address*)&pkt->buffer[6] == ps2MAC)
|
||||
{
|
||||
//avoid pcap looping packets
|
||||
return false;
|
||||
@@ -347,8 +346,8 @@ bool NetAdapter::InternalServerRecv(NetPacket* pkt)
|
||||
ippkt->destinationIP = {{{255, 255, 255, 255}}};
|
||||
ippkt->sourceIP = internalIP;
|
||||
EthernetFrame frame(ippkt);
|
||||
memcpy(frame.sourceMAC, internalMAC, 6);
|
||||
memcpy(frame.destinationMAC, ps2MAC, 6);
|
||||
frame.sourceMAC = internalMAC;
|
||||
frame.destinationMAC = ps2MAC;
|
||||
frame.protocol = (u16)EtherType::IPv4;
|
||||
frame.WritePacket(pkt);
|
||||
return true;
|
||||
@@ -361,8 +360,8 @@ bool NetAdapter::InternalServerRecv(NetPacket* pkt)
|
||||
ippkt->destinationIP = ps2IP;
|
||||
ippkt->sourceIP = internalIP;
|
||||
EthernetFrame frame(ippkt);
|
||||
memcpy(frame.sourceMAC, internalMAC, 6);
|
||||
memcpy(frame.destinationMAC, ps2MAC, 6);
|
||||
frame.sourceMAC = internalMAC;
|
||||
frame.destinationMAC = ps2MAC;
|
||||
frame.protocol = (u16)EtherType::IPv4;
|
||||
frame.WritePacket(pkt);
|
||||
InspectRecv(pkt);
|
||||
|
||||
+6
-5
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "PacketReader/MAC_Address.h"
|
||||
#include "PacketReader/IP/IP_Address.h"
|
||||
#include "InternalServers/DHCP_Server.h"
|
||||
#include "InternalServers/DNS_Logger.h"
|
||||
@@ -42,7 +43,7 @@
|
||||
struct ConfigDEV9;
|
||||
|
||||
// first three recognized by Xlink as Sony PS2
|
||||
const u8 defaultMAC[6] = {0x00, 0x04, 0x1F, 0x82, 0x30, 0x31};
|
||||
const PacketReader::MAC_Address defaultMAC = {{{0x00, 0x04, 0x1F, 0x82, 0x30, 0x31}}};
|
||||
|
||||
struct NetPacket
|
||||
{
|
||||
@@ -93,9 +94,9 @@ public:
|
||||
static const PacketReader::IP::IP_Address internalIP;
|
||||
|
||||
protected:
|
||||
u8 ps2MAC[6];
|
||||
static const u8 broadcastMAC[6];
|
||||
static const u8 internalMAC[6];
|
||||
PacketReader::MAC_Address ps2MAC;
|
||||
static const PacketReader::MAC_Address broadcastMAC;
|
||||
static const PacketReader::MAC_Address internalMAC;
|
||||
|
||||
private:
|
||||
//Only set if packet sent to the internal IP address
|
||||
@@ -126,7 +127,7 @@ public:
|
||||
virtual ~NetAdapter();
|
||||
|
||||
protected:
|
||||
void SetMACAddress(u8* mac);
|
||||
void SetMACAddress(PacketReader::MAC_Address* mac);
|
||||
bool VerifyPkt(NetPacket* pkt, int read_size);
|
||||
|
||||
void InspectRecv(NetPacket* pkt);
|
||||
|
||||
+213
-302
@@ -23,22 +23,16 @@
|
||||
#include "common/StringUtil.h"
|
||||
#include <WinSock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(__POSIX__)
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "pcap_io.h"
|
||||
#include "DEV9.h"
|
||||
#include "AdapterUtils.h"
|
||||
#include "net.h"
|
||||
#include "PacketReader/EthernetFrame.h"
|
||||
#include "PacketReader/EthernetFrameEditor.h"
|
||||
#include "PacketReader/ARP/ARP_PacketEditor.h"
|
||||
#ifndef PCAP_NETMASK_UNKNOWN
|
||||
#define PCAP_NETMASK_UNKNOWN 0xffffffff
|
||||
#endif
|
||||
@@ -47,237 +41,9 @@
|
||||
#define PCAPPREFIX "\\Device\\NPF_"
|
||||
#endif
|
||||
|
||||
pcap_t* adhandle;
|
||||
pcap_dumper_t* dump_pcap = nullptr;
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
int pcap_io_running = 0;
|
||||
bool pcap_io_switched;
|
||||
bool pcap_io_blocking;
|
||||
|
||||
extern u8 eeprom[];
|
||||
|
||||
char namebuff[256];
|
||||
|
||||
ip_address ps2_ip;
|
||||
mac_address ps2_mac;
|
||||
mac_address host_mac;
|
||||
|
||||
// Fetches the MAC address and prints it
|
||||
int GetMACAddress(const std::string& adapter, mac_address* addr)
|
||||
{
|
||||
int retval = 0;
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapterInfo;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
if (AdapterUtils::GetWin32Adapter(adapter, &adapterInfo, &buffer))
|
||||
{
|
||||
memcpy(addr, adapterInfo.PhysicalAddress, 6);
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
struct ifreq ifr;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
strcpy(ifr.ifr_name, adapter.c_str());
|
||||
if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr))
|
||||
{
|
||||
retval = 1;
|
||||
memcpy(addr, ifr.ifr_hwaddr.sa_data, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Could not get MAC address for adapter: %s", adapter.c_str());
|
||||
}
|
||||
close(fd);
|
||||
#else
|
||||
Console.Error("Could not get MAC address for adapter, OS not supported");
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
int pcap_io_init(const std::string& adapter, bool switched, mac_address virtual_mac)
|
||||
{
|
||||
struct bpf_program fp;
|
||||
char filter[1024] = "ether broadcast or ether dst ";
|
||||
int dlt;
|
||||
char* dlt_name;
|
||||
Console.WriteLn("DEV9: Opening adapter '%s'...", adapter.c_str());
|
||||
|
||||
pcap_io_switched = switched;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string pcapAdapter = PCAPPREFIX + adapter;
|
||||
#else
|
||||
std::string pcapAdapter = adapter;
|
||||
#endif
|
||||
/* Open the adapter */
|
||||
if ((adhandle = pcap_open_live(pcapAdapter.c_str(), // name of the device
|
||||
65536, // portion of the packet to capture.
|
||||
// 65536 grants that the whole packet will be captured on all the MACs.
|
||||
switched ? 1 : 0,
|
||||
1, // read timeout
|
||||
errbuf // error buffer
|
||||
)) == NULL)
|
||||
{
|
||||
Console.Error("DEV9: %s", errbuf);
|
||||
Console.Error("DEV9: Unable to open the adapter. %s is not supported by pcap", adapter.c_str());
|
||||
return -1;
|
||||
}
|
||||
if (switched)
|
||||
{
|
||||
char virtual_mac_str[18];
|
||||
sprintf(virtual_mac_str, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", virtual_mac.bytes[0], virtual_mac.bytes[1], virtual_mac.bytes[2], virtual_mac.bytes[3], virtual_mac.bytes[4], virtual_mac.bytes[5]);
|
||||
strcat(filter, virtual_mac_str);
|
||||
// fprintf(stderr, "Trying pcap filter: %s\n", filter);
|
||||
|
||||
if (pcap_compile(adhandle, &fp, filter, 1, PCAP_NETMASK_UNKNOWN) == -1)
|
||||
{
|
||||
Console.Error("DEV9: Error calling pcap_compile: %s", pcap_geterr(adhandle));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pcap_setfilter(adhandle, &fp) == -1)
|
||||
{
|
||||
Console.Error("DEV9: Error setting filter: %s", pcap_geterr(adhandle));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcap_setnonblock(adhandle, 1, errbuf) == -1)
|
||||
{
|
||||
Console.Error("DEV9: Error setting non-blocking: %s", pcap_geterr(adhandle));
|
||||
Console.Error("DEV9: Continuing in blocking mode");
|
||||
pcap_io_blocking = true;
|
||||
}
|
||||
else
|
||||
pcap_io_blocking = false;
|
||||
|
||||
dlt = pcap_datalink(adhandle);
|
||||
dlt_name = (char*)pcap_datalink_val_to_name(dlt);
|
||||
|
||||
Console.Error("DEV9: Device uses DLT %d: %s", dlt, dlt_name);
|
||||
switch (dlt)
|
||||
{
|
||||
case DLT_EN10MB:
|
||||
//case DLT_IEEE802_11:
|
||||
break;
|
||||
default:
|
||||
Console.Error("ERROR: Unsupported DataLink Type (%d): %s", dlt, dlt_name);
|
||||
pcap_close(adhandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
const std::string plfile(s_strLogPath + "/pkt_log.pcap");
|
||||
dump_pcap = pcap_dump_open(adhandle, plfile.c_str());
|
||||
#endif
|
||||
|
||||
pcap_io_running = 1;
|
||||
Console.WriteLn("DEV9: Adapter Ok.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int gettimeofday(struct timeval* tv, void* tz)
|
||||
{
|
||||
unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||
|
||||
GetSystemTimeAsFileTime((LPFILETIME)&ns100);
|
||||
tv->tv_usec = (long)((ns100 / 10L) % 1000000L);
|
||||
tv->tv_sec = (long)((ns100 - 116444736000000000L) / 10000000L);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int pcap_io_send(void* packet, int plen)
|
||||
{
|
||||
if (pcap_io_running <= 0)
|
||||
return -1;
|
||||
|
||||
if (!pcap_io_switched)
|
||||
{
|
||||
if (((ethernet_header*)packet)->protocol == 0x0008) //IP
|
||||
{
|
||||
ps2_ip = ((ip_header*)((u8*)packet + sizeof(ethernet_header)))->src;
|
||||
}
|
||||
if (((ethernet_header*)packet)->protocol == 0x0608) //ARP
|
||||
{
|
||||
ps2_ip = ((arp_packet*)((u8*)packet + sizeof(ethernet_header)))->p_src;
|
||||
((arp_packet*)((u8*)packet + sizeof(ethernet_header)))->h_src = host_mac;
|
||||
}
|
||||
((ethernet_header*)packet)->src = host_mac;
|
||||
}
|
||||
|
||||
if (dump_pcap)
|
||||
{
|
||||
static struct pcap_pkthdr ph;
|
||||
gettimeofday(&ph.ts, NULL);
|
||||
ph.caplen = plen;
|
||||
ph.len = plen;
|
||||
pcap_dump((u_char*)dump_pcap, &ph, (u_char*)packet);
|
||||
}
|
||||
|
||||
return pcap_sendpacket(adhandle, (u_char*)packet, plen);
|
||||
}
|
||||
|
||||
int pcap_io_recv(void* packet, int max_len)
|
||||
{
|
||||
static struct pcap_pkthdr* header;
|
||||
static const u_char* pkt_data1;
|
||||
|
||||
if (pcap_io_running <= 0)
|
||||
return -1;
|
||||
|
||||
if ((pcap_next_ex(adhandle, &header, &pkt_data1)) > 0)
|
||||
{
|
||||
if ((int)header->len > max_len)
|
||||
return -1;
|
||||
|
||||
memcpy(packet, pkt_data1, header->len);
|
||||
|
||||
if (!pcap_io_switched)
|
||||
{
|
||||
{
|
||||
if (((ethernet_header*)packet)->protocol == 0x0008)
|
||||
{
|
||||
ip_header* iph = ((ip_header*)((u8*)packet + sizeof(ethernet_header)));
|
||||
if (ip_compare(iph->dst, ps2_ip) == 0)
|
||||
{
|
||||
((ethernet_header*)packet)->dst = ps2_mac;
|
||||
}
|
||||
}
|
||||
if (((ethernet_header*)packet)->protocol == 0x0608)
|
||||
{
|
||||
arp_packet* aph = ((arp_packet*)((u8*)packet + sizeof(ethernet_header)));
|
||||
if (ip_compare(aph->p_dst, ps2_ip) == 0)
|
||||
{
|
||||
((ethernet_header*)packet)->dst = ps2_mac;
|
||||
((arp_packet*)((u8*)packet + sizeof(ethernet_header)))->h_dst = ps2_mac;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_pcap)
|
||||
pcap_dump((u_char*)dump_pcap, header, (u_char*)packet);
|
||||
|
||||
return header->len;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pcap_io_close()
|
||||
{
|
||||
if (dump_pcap)
|
||||
pcap_dump_close(dump_pcap);
|
||||
if (adhandle)
|
||||
pcap_close(adhandle);
|
||||
pcap_io_running = 0;
|
||||
}
|
||||
|
||||
using namespace PacketReader;
|
||||
using namespace PacketReader::ARP;
|
||||
using namespace PacketReader::IP;
|
||||
|
||||
PCAPAdapter::PCAPAdapter()
|
||||
: NetAdapter()
|
||||
@@ -289,50 +55,62 @@ PCAPAdapter::PCAPAdapter()
|
||||
return;
|
||||
#endif
|
||||
|
||||
mac_address hostMAC;
|
||||
mac_address newMAC;
|
||||
#ifdef _WIN32
|
||||
std::string pcapAdapter = PCAPPREFIX + EmuConfig.DEV9.EthDevice;
|
||||
#else
|
||||
std::string pcapAdapter = EmuConfig.DEV9.EthDevice;
|
||||
#endif
|
||||
|
||||
GetMACAddress(EmuConfig.DEV9.EthDevice, &hostMAC);
|
||||
memcpy(&newMAC, ps2MAC, 6);
|
||||
switched = EmuConfig.DEV9.EthApi == Pcsx2Config::DEV9Options::NetApi::PCAP_Switched;
|
||||
|
||||
//Lets take the hosts last 2 bytes to make it unique on Xlink
|
||||
newMAC.bytes[5] = hostMAC.bytes[4];
|
||||
newMAC.bytes[4] = hostMAC.bytes[5];
|
||||
|
||||
SetMACAddress((u8*)&newMAC);
|
||||
host_mac = hostMAC;
|
||||
ps2_mac = newMAC; //Needed outside of this class
|
||||
|
||||
if (pcap_io_init(EmuConfig.DEV9.EthDevice, EmuConfig.DEV9.EthApi == Pcsx2Config::DEV9Options::NetApi::PCAP_Switched, newMAC) == -1)
|
||||
if (!InitPCAP(pcapAdapter, switched))
|
||||
{
|
||||
Console.Error("DEV9: Can't open Device '%s'", EmuConfig.DEV9.EthDevice.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
if (AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
InitInternalServer(&adapter);
|
||||
AdapterUtils::Adapter adapter;
|
||||
AdapterUtils::AdapterBuffer buffer;
|
||||
std::optional<MAC_Address> adMAC = std::nullopt;
|
||||
const bool foundAdapter = AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
if (foundAdapter)
|
||||
adMAC = AdapterUtils::GetAdapterMAC(&adapter);
|
||||
else
|
||||
Console.Error("DEV9: Failed to get adapter information");
|
||||
|
||||
if (adMAC.has_value())
|
||||
{
|
||||
hostMAC = adMAC.value();
|
||||
MAC_Address newMAC = ps2MAC;
|
||||
|
||||
//Lets take the hosts last 2 bytes to make it unique on Xlink
|
||||
newMAC.bytes[5] = hostMAC.bytes[4];
|
||||
newMAC.bytes[4] = hostMAC.bytes[5];
|
||||
|
||||
SetMACAddress(&newMAC);
|
||||
}
|
||||
else if (switched)
|
||||
Console.Error("DEV9: Failed to get MAC address for adapter, proceeding with hardcoded MAC address");
|
||||
else
|
||||
{
|
||||
Console.Error("DEV9: Failed to get adapter information");
|
||||
InitInternalServer(nullptr);
|
||||
Console.Error("DEV9: Failed to get MAC address for adapter");
|
||||
pcap_close(hpcap);
|
||||
hpcap = nullptr;
|
||||
return;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
if (AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
|
||||
if (switched && !SetMACSwitchedFilter(ps2MAC))
|
||||
{
|
||||
pcap_close(hpcap);
|
||||
hpcap = nullptr;
|
||||
Console.Error("DEV9: Can't open Device '%s'", EmuConfig.DEV9.EthDevice.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (foundAdapter)
|
||||
InitInternalServer(&adapter);
|
||||
freeifaddrs(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("DEV9: Failed to get adapter information");
|
||||
InitInternalServer(nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
AdapterOptions PCAPAdapter::GetAdapterOptions()
|
||||
{
|
||||
@@ -340,70 +118,88 @@ AdapterOptions PCAPAdapter::GetAdapterOptions()
|
||||
}
|
||||
bool PCAPAdapter::blocks()
|
||||
{
|
||||
pxAssert(pcap_io_running);
|
||||
return pcap_io_blocking;
|
||||
pxAssert(hpcap);
|
||||
return blocking;
|
||||
}
|
||||
bool PCAPAdapter::isInitialised()
|
||||
{
|
||||
return !!pcap_io_running;
|
||||
return hpcap != nullptr;
|
||||
}
|
||||
//gets a packet.rv :true success
|
||||
bool PCAPAdapter::recv(NetPacket* pkt)
|
||||
{
|
||||
if (!pcap_io_blocking && NetAdapter::recv(pkt))
|
||||
pxAssert(hpcap);
|
||||
|
||||
if (!blocking && NetAdapter::recv(pkt))
|
||||
return true;
|
||||
|
||||
int size = pcap_io_recv(pkt->buffer, sizeof(pkt->buffer));
|
||||
if (size > 0 && VerifyPkt(pkt, size))
|
||||
pcap_pkthdr* header;
|
||||
const u_char* pkt_data;
|
||||
|
||||
// pcap bridged will pick up packets not intended for us, returning false on those packets will incur a 1ms wait.
|
||||
// This delays getting packets we need, so instead loop untill a valid packet, or no packet, is returned from pcap_next_ex.
|
||||
while (pcap_next_ex(hpcap, &header, &pkt_data) > 0)
|
||||
{
|
||||
InspectRecv(pkt);
|
||||
return true;
|
||||
if (header->len > sizeof(pkt->buffer))
|
||||
{
|
||||
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
|
||||
continue;
|
||||
}
|
||||
|
||||
pxAssert(header->len == header->caplen);
|
||||
|
||||
memcpy(pkt->buffer, pkt_data, header->len);
|
||||
pkt->size = (int)header->len;
|
||||
|
||||
if (!switched)
|
||||
SetMACBridgedRecv(pkt);
|
||||
|
||||
if (VerifyPkt(pkt, header->len))
|
||||
{
|
||||
InspectRecv(pkt);
|
||||
return true;
|
||||
}
|
||||
// continue.
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
//sends the packet .rv :true success
|
||||
bool PCAPAdapter::send(NetPacket* pkt)
|
||||
{
|
||||
pxAssert(hpcap);
|
||||
|
||||
InspectSend(pkt);
|
||||
if (NetAdapter::send(pkt))
|
||||
return true;
|
||||
|
||||
if (pcap_io_send(pkt->buffer, pkt->size))
|
||||
{
|
||||
// TODO: loopback broadcast packets to host pc in switched mode.
|
||||
if (!switched)
|
||||
SetMACBridgedSend(pkt);
|
||||
|
||||
if (pcap_sendpacket(hpcap, (u_char*)pkt->buffer, pkt->size))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PCAPAdapter::reloadSettings()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
if (AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
AdapterUtils::Adapter adapter;
|
||||
AdapterUtils::AdapterBuffer buffer;
|
||||
if (AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
ReloadInternalServer(&adapter);
|
||||
else
|
||||
ReloadInternalServer(nullptr);
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
if (AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
{
|
||||
ReloadInternalServer(&adapter);
|
||||
freeifaddrs(buffer);
|
||||
}
|
||||
else
|
||||
ReloadInternalServer(nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
PCAPAdapter::~PCAPAdapter()
|
||||
{
|
||||
pcap_io_close();
|
||||
if (hpcap)
|
||||
{
|
||||
pcap_close(hpcap);
|
||||
hpcap = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
@@ -415,6 +211,7 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
return nic;
|
||||
#endif
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
pcap_if_t* alldevs;
|
||||
pcap_if_t* d;
|
||||
|
||||
@@ -440,7 +237,7 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
IP_ADAPTER_ADDRESSES adapterInfo;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
if (AdapterUtils::GetWin32Adapter(entry.guid, &adapterInfo, &buffer))
|
||||
if (AdapterUtils::GetAdapter(entry.guid, &adapterInfo, &buffer))
|
||||
entry.name = StringUtil::WideStringToUTF8String(std::wstring(adapterInfo.FriendlyName));
|
||||
else
|
||||
{
|
||||
@@ -470,3 +267,117 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
|
||||
return nic;
|
||||
}
|
||||
|
||||
// Opens device for capture and sets non-blocking.
|
||||
bool PCAPAdapter::InitPCAP(const std::string& adapter, bool promiscuous)
|
||||
{
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
Console.WriteLn("DEV9: Opening adapter '%s'...", adapter.c_str());
|
||||
|
||||
// Open the adapter.
|
||||
if ((hpcap = pcap_open_live(adapter.c_str(), // Name of the device.
|
||||
65536, // portion of the packet to capture.
|
||||
// 65536 grants that the whole packet will be captured on all the MACs.
|
||||
promiscuous ? 1 : 0,
|
||||
1, // Read timeout.
|
||||
errbuf // Error buffer.
|
||||
)) == nullptr)
|
||||
{
|
||||
Console.Error("DEV9: %s", errbuf);
|
||||
Console.Error("DEV9: Unable to open the adapter. %s is not supported by pcap", adapter.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pcap_setnonblock(hpcap, 1, errbuf) == -1)
|
||||
{
|
||||
Console.Error("DEV9: Error setting non-blocking: %s", pcap_geterr(hpcap));
|
||||
Console.Error("DEV9: Continuing in blocking mode");
|
||||
blocking = true;
|
||||
}
|
||||
else
|
||||
blocking = false;
|
||||
|
||||
// Validate.
|
||||
const int dlt = pcap_datalink(hpcap);
|
||||
const char* dlt_name = pcap_datalink_val_to_name(dlt);
|
||||
|
||||
Console.Error("DEV9: Device uses DLT %d: %s", dlt, dlt_name);
|
||||
switch (dlt)
|
||||
{
|
||||
case DLT_EN10MB:
|
||||
//case DLT_IEEE802_11:
|
||||
break;
|
||||
default:
|
||||
Console.Error("ERROR: Unsupported DataLink Type (%d): %s", dlt, dlt_name);
|
||||
pcap_close(hpcap);
|
||||
hpcap = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn("DEV9: Adapter Ok.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PCAPAdapter::SetMACSwitchedFilter(MAC_Address mac)
|
||||
{
|
||||
bpf_program fp;
|
||||
char filter[1024] = "ether broadcast or ether dst ";
|
||||
|
||||
char virtual_mac_str[18];
|
||||
sprintf(virtual_mac_str, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac.bytes[0], mac.bytes[1], mac.bytes[2], mac.bytes[3], mac.bytes[4], mac.bytes[5]);
|
||||
strcat(filter, virtual_mac_str);
|
||||
|
||||
if (pcap_compile(hpcap, &fp, filter, 1, PCAP_NETMASK_UNKNOWN) == -1)
|
||||
{
|
||||
Console.Error("DEV9: Error calling pcap_compile: %s", pcap_geterr(hpcap));
|
||||
return false;
|
||||
}
|
||||
|
||||
int setFilterRet;
|
||||
if ((setFilterRet = pcap_setfilter(hpcap, &fp)) == -1)
|
||||
Console.Error("DEV9: Error setting filter: %s", pcap_geterr(hpcap));
|
||||
|
||||
pcap_freecode(&fp);
|
||||
return setFilterRet != -1;
|
||||
}
|
||||
|
||||
void PCAPAdapter::SetMACBridgedRecv(NetPacket* pkt)
|
||||
{
|
||||
EthernetFrameEditor frame(pkt);
|
||||
if (frame.GetProtocol() == (u16)EtherType::IPv4) // IP
|
||||
{
|
||||
// Compare DEST IP in IP with the PS2's IP, if they match, change DEST MAC to ps2MAC.
|
||||
PayloadPtr* payload = frame.GetPayload();
|
||||
IP_Packet ippkt(payload->data, payload->GetLength());
|
||||
if (ippkt.destinationIP == ps2IP)
|
||||
frame.SetDestinationMAC(ps2MAC);
|
||||
}
|
||||
if (frame.GetProtocol() == (u16)EtherType::ARP) // ARP
|
||||
{
|
||||
// Compare DEST IP in ARP with the PS2's IP, if they match, DEST MAC to ps2MAC on both ARP and ETH Packet headers.
|
||||
ARP_PacketEditor arpPkt(frame.GetPayload());
|
||||
if (*(IP_Address*)arpPkt.TargetProtocolAddress() == ps2IP)
|
||||
{
|
||||
frame.SetDestinationMAC(ps2MAC);
|
||||
*(MAC_Address*)arpPkt.TargetHardwareAddress() = ps2MAC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PCAPAdapter::SetMACBridgedSend(NetPacket* pkt)
|
||||
{
|
||||
EthernetFrameEditor frame(pkt);
|
||||
if (frame.GetProtocol() == (u16)EtherType::IPv4) // IP
|
||||
{
|
||||
PayloadPtr* payload = frame.GetPayload();
|
||||
IP_Packet ippkt(payload->data, payload->GetLength());
|
||||
ps2IP = ippkt.sourceIP;
|
||||
}
|
||||
if (frame.GetProtocol() == (u16)EtherType::ARP) // ARP
|
||||
{
|
||||
ARP_PacketEditor arpPkt(frame.GetPayload());
|
||||
ps2IP = *(IP_Address*)arpPkt.SenderProtocolAddress();
|
||||
*(MAC_Address*)arpPkt.SenderHardwareAddress() = hostMAC;
|
||||
}
|
||||
frame.SetSourceMAC(hostMAC);
|
||||
}
|
||||
|
||||
+18
-149
@@ -16,163 +16,24 @@
|
||||
#pragma once
|
||||
#include "pcap.h"
|
||||
#include "net.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
//#ifndef _WIN32
|
||||
#pragma pack(push, 1)
|
||||
typedef struct _ip_address
|
||||
{
|
||||
u_char bytes[4];
|
||||
} ip_address;
|
||||
|
||||
typedef struct _mac_address
|
||||
{
|
||||
u_char bytes[6];
|
||||
} mac_address;
|
||||
|
||||
typedef struct _ethernet_header
|
||||
{
|
||||
mac_address dst;
|
||||
mac_address src;
|
||||
u_short protocol;
|
||||
} ethernet_header;
|
||||
|
||||
typedef struct _arp_packet
|
||||
{
|
||||
u_short hw_type;
|
||||
u_short protocol;
|
||||
u_char h_addr_len;
|
||||
u_char p_addr_len;
|
||||
u_short operation;
|
||||
mac_address h_src;
|
||||
ip_address p_src;
|
||||
mac_address h_dst;
|
||||
ip_address p_dst;
|
||||
} arp_packet;
|
||||
|
||||
typedef struct _ip_header
|
||||
{
|
||||
u_char ver_hlen; /* version << 4 | header length >> 2 */
|
||||
u_char type; /* type of service */
|
||||
u_short len; /* total length */
|
||||
u_short id; /* identification */
|
||||
u_short offset; /* fragment offset field */
|
||||
u_char ttl; /* time to live */
|
||||
u_char proto; /* protocol */
|
||||
u_short hdr_csum; /* checksum */
|
||||
ip_address src; /* source and dest address */
|
||||
ip_address dst;
|
||||
} ip_header;
|
||||
|
||||
/* Internet Control Message Protocol Constants and Packet Format */
|
||||
|
||||
/* ic_type field */
|
||||
#define ICT_ECHORP 0 /* Echo reply */
|
||||
#define ICT_DESTUR 3 /* Destination unreachable */
|
||||
#define ICT_SRCQ 4 /* Source quench */
|
||||
#define ICT_REDIRECT 5 /* Redirect message type */
|
||||
#define ICT_ECHORQ 8 /* Echo request */
|
||||
#define ICT_TIMEX 11 /* Time exceeded */
|
||||
#define ICT_PARAMP 12 /* Parameter Problem */
|
||||
#define ICT_TIMERQ 13 /* Timestamp request */
|
||||
#define ICT_TIMERP 14 /* Timestamp reply */
|
||||
#define ICT_INFORQ 15 /* Information request */
|
||||
#define ICT_INFORP 16 /* Information reply */
|
||||
#define ICT_MASKRQ 17 /* Mask request */
|
||||
#define ICT_MASKRP 18 /* Mask reply */
|
||||
|
||||
/* ic_code field */
|
||||
#define ICC_NETUR 0 /* dest unreachable, net unreachable */
|
||||
#define ICC_HOSTUR 1 /* dest unreachable, host unreachable */
|
||||
#define ICC_PROTOUR 2 /* dest unreachable, proto unreachable */
|
||||
#define ICC_PORTUR 3 /* dest unreachable, port unreachable */
|
||||
#define ICC_FNADF 4 /* dest unr, frag needed & don't frag */
|
||||
#define ICC_SRCRT 5 /* dest unreachable, src route failed */
|
||||
|
||||
#define ICC_NETRD 0 /* redirect: net */
|
||||
#define ICC_HOSTRD 1 /* redirect: host */
|
||||
#define IC_TOSNRD 2 /* redirect: type of service, net */
|
||||
#define IC_TOSHRD 3 /* redirect: type of service, host */
|
||||
|
||||
#define ICC_TIMEX 0 /* time exceeded, ttl */
|
||||
#define ICC_FTIMEX 1 /* time exceeded, frag */
|
||||
|
||||
#define IC_HLEN 8 /* octets */
|
||||
#define IC_PADLEN 3 /* pad length (octets) */
|
||||
|
||||
#define IC_RDTTL 300 /* ttl for redirect routes */
|
||||
|
||||
|
||||
/* ICMP packet format (following the IP header) */
|
||||
typedef struct _icmp_header
|
||||
{ /* ICMP packet */
|
||||
char type; /* type of message (ICT_* above)*/
|
||||
char code; /* code (ICC_* above) */
|
||||
short csum; /* checksum of ICMP header+data */
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int ic1_id : 16; /* echo type, a message id */
|
||||
int ic1_seq : 16; /* echo type, a seq. number */
|
||||
} ic1;
|
||||
ip_address ic2_gw; /* for redirect, gateway */
|
||||
struct
|
||||
{
|
||||
char ic3_ptr; /* pointer, for ICT_PARAMP */
|
||||
char ic3_pad[IC_PADLEN];
|
||||
} ic3;
|
||||
int ic4_mbz; /* must be zero */
|
||||
} icu;
|
||||
} icmp_header;
|
||||
|
||||
/*typedef struct _udp_header {
|
||||
u16 src_port;
|
||||
u16 dst_port;
|
||||
u16 len;
|
||||
u16 csum;
|
||||
} udp_header;*/
|
||||
|
||||
typedef struct _full_arp_packet
|
||||
{
|
||||
ethernet_header header;
|
||||
arp_packet arp;
|
||||
} full_arp_packet;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#define ARP_REQUEST 0x0100 //values are big-endian
|
||||
|
||||
#define mac_compare(a, b) (memcmp(&(a), &(b), 6))
|
||||
#define ip_compare(a, b) (memcmp(&(a), &(b), 4))
|
||||
|
||||
//#endif
|
||||
/*
|
||||
int pcap_io_init(char *adapter);
|
||||
int pcap_io_send(void* packet, int plen);
|
||||
int pcap_io_recv(void* packet, int max_len);
|
||||
void pcap_io_close();
|
||||
int pcap_io_get_dev_num();
|
||||
char* pcap_io_get_dev_desc(int num);
|
||||
char* pcap_io_get_dev_name(int num);
|
||||
*/
|
||||
#include "PacketReader/MAC_Address.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
bool load_pcap();
|
||||
void unload_pcap();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class PCAPAdapter : public NetAdapter
|
||||
{
|
||||
private:
|
||||
pcap_t* hpcap = nullptr;
|
||||
|
||||
bool switched;
|
||||
bool blocking;
|
||||
|
||||
PacketReader::IP::IP_Address ps2IP{};
|
||||
PacketReader::MAC_Address hostMAC;
|
||||
|
||||
public:
|
||||
PCAPAdapter();
|
||||
virtual bool blocks();
|
||||
@@ -185,4 +46,12 @@ public:
|
||||
virtual ~PCAPAdapter();
|
||||
static std::vector<AdapterEntry> GetAdapters();
|
||||
static AdapterOptions GetAdapterOptions();
|
||||
|
||||
private:
|
||||
bool InitPCAP(const std::string& adapter, bool promiscuous);
|
||||
void InitPCAPDumper();
|
||||
bool SetMACSwitchedFilter(PacketReader::MAC_Address mac);
|
||||
|
||||
void SetMACBridgedRecv(NetPacket* pkt);
|
||||
void SetMACBridgedSend(NetPacket* pkt);
|
||||
};
|
||||
|
||||
+32
-105
@@ -27,10 +27,6 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "sockets.h"
|
||||
@@ -160,13 +156,12 @@ SocketAdapter::SocketAdapter()
|
||||
{
|
||||
bool foundAdapter;
|
||||
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
AdapterUtils::Adapter adapter;
|
||||
AdapterUtils::AdapterBuffer buffer;
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
{
|
||||
foundAdapter = AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
|
||||
if (!foundAdapter)
|
||||
{
|
||||
@@ -185,7 +180,7 @@ SocketAdapter::SocketAdapter()
|
||||
}
|
||||
else
|
||||
{
|
||||
foundAdapter = AdapterUtils::GetWin32AdapterAuto(&adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetAdapterAuto(&adapter, &buffer);
|
||||
adapterIP = {};
|
||||
|
||||
if (!foundAdapter)
|
||||
@@ -194,42 +189,6 @@ SocketAdapter::SocketAdapter()
|
||||
return;
|
||||
}
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
{
|
||||
foundAdapter = AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
|
||||
if (!foundAdapter)
|
||||
{
|
||||
Console.Error("DEV9: Socket: Failed to Get Adapter");
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<IP_Address> adIP = AdapterUtils::GetAdapterIP(&adapter);
|
||||
if (adIP.has_value())
|
||||
adapterIP = adIP.value();
|
||||
else
|
||||
{
|
||||
Console.Error("DEV9: Socket: Failed To Get Adapter IP");
|
||||
freeifaddrs(buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foundAdapter = AdapterUtils::GetIfAdapterAuto(&adapter, &buffer);
|
||||
adapterIP = {0};
|
||||
|
||||
if (!foundAdapter)
|
||||
{
|
||||
Console.Error("DEV9: Socket: Auto Selection Failed, Check You Connection or Manually Specify Adapter");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//For DHCP, we need to override some settings
|
||||
//DNS settings as per direct adapters
|
||||
@@ -239,38 +198,21 @@ SocketAdapter::SocketAdapter()
|
||||
const IP_Address gateway = internalIP;
|
||||
|
||||
InitInternalServer(&adapter, true, ps2IP, subnet, gateway);
|
||||
#ifdef __POSIX__
|
||||
freeifaddrs(buffer);
|
||||
#endif
|
||||
|
||||
u8 hostMAC[6];
|
||||
u8 newMAC[6];
|
||||
|
||||
#ifdef _WIN32
|
||||
memcpy(hostMAC, adapter.PhysicalAddress, 6);
|
||||
#elif defined(__linux__)
|
||||
struct ifreq ifr;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
strcpy(ifr.ifr_name, adapter.ifa_name);
|
||||
if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr))
|
||||
memcpy(hostMAC, ifr.ifr_hwaddr.sa_data, 6);
|
||||
else
|
||||
std::optional<MAC_Address> adMAC = AdapterUtils::GetAdapterMAC(&adapter);
|
||||
if (adMAC.has_value())
|
||||
{
|
||||
memcpy(hostMAC, ps2MAC, 6);
|
||||
Console.Error("Could not get MAC address for adapter: %s", adapter.ifa_name);
|
||||
MAC_Address hostMAC = adMAC.value();
|
||||
MAC_Address newMAC = ps2MAC;
|
||||
|
||||
//Lets take the hosts last 2 bytes to make it unique on Xlink
|
||||
newMAC.bytes[5] = hostMAC.bytes[4];
|
||||
newMAC.bytes[4] = hostMAC.bytes[5];
|
||||
|
||||
SetMACAddress(&newMAC);
|
||||
}
|
||||
::close(fd);
|
||||
#else
|
||||
memcpy(hostMAC, ps2MAC, 6);
|
||||
Console.Error("Could not get MAC address for adapter, OS not supported");
|
||||
#endif
|
||||
memcpy(newMAC, ps2MAC, 6);
|
||||
|
||||
//Lets take the hosts last 2 bytes to make it unique on Xlink
|
||||
newMAC[5] = hostMAC[4];
|
||||
newMAC[4] = hostMAC[5];
|
||||
|
||||
SetMACAddress(newMAC);
|
||||
else
|
||||
Console.Error("DEV9: Socket: Failed to get MAC address for adapter");
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
|
||||
@@ -326,8 +268,8 @@ bool SocketAdapter::recv(NetPacket* pkt)
|
||||
ipPkt->sourceIP = session->destIP;
|
||||
|
||||
EthernetFrame frame(ipPkt);
|
||||
memcpy(frame.sourceMAC, internalMAC, 6);
|
||||
memcpy(frame.destinationMAC, ps2MAC, 6);
|
||||
frame.sourceMAC = internalMAC;
|
||||
frame.destinationMAC = ps2MAC;
|
||||
frame.protocol = (u16)EtherType::IPv4;
|
||||
|
||||
frame.WritePacket(pkt);
|
||||
@@ -384,17 +326,17 @@ bool SocketAdapter::send(NetPacket* pkt)
|
||||
//it's trying to resolve the virtual gateway's mac addr
|
||||
{
|
||||
ARP_Packet* arpRet = new ARP_Packet(6, 4);
|
||||
memcpy(arpRet->targetHardwareAddress.get(), arpPkt.senderHardwareAddress.get(), 6);
|
||||
memcpy(arpRet->senderHardwareAddress.get(), internalMAC, 6);
|
||||
memcpy(arpRet->targetProtocolAddress.get(), arpPkt.senderProtocolAddress.get(), 4);
|
||||
memcpy(arpRet->senderProtocolAddress.get(), arpPkt.targetProtocolAddress.get(), 4);
|
||||
*(MAC_Address*)arpRet->targetHardwareAddress.get() = *(MAC_Address*)arpPkt.senderHardwareAddress.get();
|
||||
*(MAC_Address*)arpRet->senderHardwareAddress.get() = internalMAC;
|
||||
*(IP_Address*)arpRet->targetProtocolAddress.get() = *(IP_Address*)arpPkt.senderProtocolAddress.get();
|
||||
*(IP_Address*)arpRet->senderProtocolAddress.get() = *(IP_Address*)arpPkt.targetProtocolAddress.get();
|
||||
arpRet->op = 2,
|
||||
arpRet->protocol = arpPkt.protocol;
|
||||
arpRet->hardwareType = arpPkt.hardwareType;
|
||||
|
||||
EthernetFrame* retARP = new EthernetFrame(arpRet);
|
||||
memcpy(retARP->destinationMAC, ps2MAC, 6);
|
||||
memcpy(retARP->sourceMAC, internalMAC, 6);
|
||||
retARP->destinationMAC = ps2MAC;
|
||||
retARP->sourceMAC = internalMAC;
|
||||
retARP->protocol = (u16)EtherType::ARP;
|
||||
|
||||
vRecBuffer.Enqueue(retARP);
|
||||
@@ -431,36 +373,21 @@ void SocketAdapter::reset()
|
||||
void SocketAdapter::reloadSettings()
|
||||
{
|
||||
bool foundAdapter = false;
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
AdapterUtils::Adapter adapter;
|
||||
AdapterUtils::AdapterBuffer buffer;
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
foundAdapter = AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
else
|
||||
foundAdapter = AdapterUtils::GetWin32AdapterAuto(&adapter, &buffer);
|
||||
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
foundAdapter = AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
else
|
||||
foundAdapter = AdapterUtils::GetIfAdapterAuto(&adapter, &buffer);
|
||||
#endif
|
||||
foundAdapter = AdapterUtils::GetAdapterAuto(&adapter, &buffer);
|
||||
|
||||
const IP_Address ps2IP = {{{internalIP.bytes[0], internalIP.bytes[1], internalIP.bytes[2], 100}}};
|
||||
const IP_Address subnet{{{255, 255, 255, 0}}};
|
||||
const IP_Address gateway = internalIP;
|
||||
|
||||
if (foundAdapter)
|
||||
{
|
||||
ReloadInternalServer(&adapter, true, ps2IP, subnet, gateway);
|
||||
#ifdef __POSIX__
|
||||
freeifaddrs(buffer);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
pxAssert(false);
|
||||
@@ -572,7 +499,7 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt)
|
||||
{
|
||||
UDP_Session* s = nullptr;
|
||||
|
||||
if (udp.sourcePort == udp.destinationPort || //Used for LAN games that assume the destination port
|
||||
if (abs(udp.sourcePort - udp.destinationPort) <= 10 || //Used for games that assume the destination/source port
|
||||
ipPkt->destinationIP == dhcpServer.broadcastIP || //Broadcast packets
|
||||
ipPkt->destinationIP == IP_Address{{{255, 255, 255, 255}}} || //Limited Broadcast packets
|
||||
(ipPkt->destinationIP.bytes[0] & 0xF0) == 0xE0) //Multicast address start with 0b1110
|
||||
@@ -591,7 +518,7 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt)
|
||||
fKey.ps2Port = udp.sourcePort;
|
||||
fKey.srvPort = 0;
|
||||
|
||||
Console.WriteLn("DEV9: Socket: Creating New UDPFixedPort with port %d", udp.destinationPort);
|
||||
Console.WriteLn("DEV9: Socket: Creating New UDPFixedPort with port %d", udp.sourcePort);
|
||||
|
||||
fPort = new UDP_FixedPort(fKey, adapterIP, udp.sourcePort);
|
||||
fPort->AddConnectionClosedHandler([&](BaseSession* session) { HandleFixedPortClosed(session); });
|
||||
@@ -603,7 +530,7 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt)
|
||||
fixedUDPPorts.Add(udp.sourcePort, fPort);
|
||||
}
|
||||
|
||||
Console.WriteLn("DEV9: Socket: Creating New UDP Connection from FixedPort %d", udp.destinationPort);
|
||||
Console.WriteLn("DEV9: Socket: Creating New UDP Connection from FixedPort %d to %d", udp.sourcePort, udp.destinationPort);
|
||||
s = fPort->NewClientSession(Key,
|
||||
ipPkt->destinationIP == dhcpServer.broadcastIP || ipPkt->destinationIP == IP_Address{{{255, 255, 255, 255}}},
|
||||
(ipPkt->destinationIP.bytes[0] & 0xF0) == 0xE0);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user