mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
579cb7bd27 | ||
|
|
aab889535f | ||
|
|
e0362f7879 | ||
|
|
009ae1fb02 | ||
|
|
d40289e977 | ||
|
|
c2fd4af163 | ||
|
|
5bdee3a611 | ||
|
|
cb026a6946 | ||
|
|
cb5124da4b | ||
|
|
7c88af9c73 | ||
|
|
465a31bbd5 | ||
|
|
6deb43bde2 | ||
|
|
8e7dcb83a8 | ||
|
|
51ead1e00f | ||
|
|
27bcb7c29a | ||
|
|
aaed4a4983 | ||
|
|
748f232976 | ||
|
|
a33612cf7d | ||
|
|
5c123f3183 | ||
|
|
d30a7fb991 | ||
|
|
d4f661c27c | ||
|
|
6d05d0220d | ||
|
|
7fab935c2d |
@@ -17,7 +17,7 @@ jobs:
|
||||
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676
|
||||
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
|
||||
with:
|
||||
title: "Qt: Update Base Translation"
|
||||
commit-message: "[ci skip] Qt: Update Base Translation."
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676
|
||||
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
|
||||
with:
|
||||
title: "PAD: Update to latest controller database"
|
||||
commit-message: "[ci skip] PAD: Update to latest controller database."
|
||||
|
||||
2
.github/workflows/linux_build_flatpak.yml
vendored
2
.github/workflows/linux_build_flatpak.yml
vendored
@@ -153,7 +153,7 @@ jobs:
|
||||
mv "./${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak" "$GITHUB_WORKSPACE"/ci-artifacts/
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: ci-artifacts
|
||||
|
||||
6
.github/workflows/linux_build_qt.yml
vendored
6
.github/workflows/linux_build_qt.yml
vendored
@@ -92,7 +92,7 @@ jobs:
|
||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: ccache cache files
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: cache-deps
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/deps
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh', '.github/workflows/scripts/common/*.patch') }}
|
||||
@@ -174,7 +174,7 @@ jobs:
|
||||
|
||||
- name: Upload artifact
|
||||
if: inputs.buildAppImage == true
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: ci-artifacts
|
||||
|
||||
6
.github/workflows/macos_build.yml
vendored
6
.github/workflows/macos_build.yml
vendored
@@ -91,7 +91,7 @@ jobs:
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: cache-deps
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/deps
|
||||
key: ${{ inputs.os }} deps ${{ hashFiles('.github/workflows/scripts/macos/*', '.github/workflows/scripts/common/*.patch') }}
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache ccache cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ inputs.os }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
@@ -197,7 +197,7 @@ jobs:
|
||||
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: "*.tar.xz"
|
||||
|
||||
2
.github/workflows/release_cut_new.yml
vendored
2
.github/workflows/release_cut_new.yml
vendored
@@ -168,7 +168,7 @@ jobs:
|
||||
- name: Prepare Artifact Folder
|
||||
run: mkdir ./ci-artifacts/
|
||||
|
||||
- uses: actions/download-artifact@v6
|
||||
- uses: actions/download-artifact@v7
|
||||
name: Download all Artifacts
|
||||
with:
|
||||
path: ./ci-artifacts/
|
||||
|
||||
6
.github/workflows/windows_build_qt.yml
vendored
6
.github/workflows/windows_build_qt.yml
vendored
@@ -115,7 +115,7 @@ jobs:
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: cache-deps
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat', '.github/workflows/scripts/common/*.patch') }}
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
cmake --build build --config Release --target unittests
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: |
|
||||
@@ -186,7 +186,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Upload artifact - with symbols
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
||||
path: |
|
||||
|
||||
@@ -13996,6 +13996,7 @@ SLED-53109:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLED-53137:
|
||||
name: "Stolen [Demo]"
|
||||
@@ -22269,6 +22270,7 @@ SLES-53044:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLES-53045:
|
||||
name: "Street Racing Syndicate"
|
||||
@@ -22592,6 +22594,7 @@ SLES-53151:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLES-53152:
|
||||
name: "Mashed Fully Loaded"
|
||||
@@ -32394,6 +32397,7 @@ SLKA-25283:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLKA-25284:
|
||||
name: "사쿠라 대전 3 ~파리는 불타고 있는가~"
|
||||
@@ -48603,6 +48607,7 @@ SLPM-66277:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLPM-66278:
|
||||
name: "新・豪血寺一族 -煩悩解放-"
|
||||
@@ -68225,6 +68230,7 @@ SLUS-20872:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLUS-20873:
|
||||
name: "Silent Hill 4 - The Room"
|
||||
@@ -75330,6 +75336,7 @@ SLUS-29147:
|
||||
cpuSpriteRenderLevel: 2 # Needed for above.
|
||||
autoFlush: 1 # Fixes headlight brightness.
|
||||
cpuCLUTRender: 1 # Fixes broken headlights.
|
||||
nativeScaling: 4 # Aligns post effects.
|
||||
minimumBlendingLevel: 3
|
||||
SLUS-29148:
|
||||
name: "The Incredible Hulk - Ultimate Destruction [Demo]"
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
03000000c82d00001230000000000000,8BitDo Ultimate,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001260000000000000,8BitDo Ultimate 2,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,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001b30000000000000,8BitDo Ultimate 2C,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,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001c30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,paddle1:b2,paddle2:b5,platform:Windows,
|
||||
03000000c82d00001c30000000000000,8BitDo Ultimate 2C,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001d30000000000000,8BitDo Ultimate 2C,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,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001530000000000000,8BitDo Ultimate C,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,
|
||||
03000000c82d00001630000000000000,8BitDo Ultimate C,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,
|
||||
@@ -985,6 +985,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000242f00002d00000007010000,JYS Adapter,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,
|
||||
030000006d04000019c2000000000000,Logitech 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,
|
||||
030000006d04000019c2000000020000,Logitech Cordless RumblePad 2,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,
|
||||
030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -993,7 +994,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006d0400001fc2000000000000,Logitech F710,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,
|
||||
030000006d04000018c2000000010000,Logitech RumblePad 2,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,
|
||||
030000006d04000019c2000000020000,Logitech Cordless RumblePad 2,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,
|
||||
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,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,
|
||||
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -1395,6 +1395,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
03000000d80400004bea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||
03000000d80400004aea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||
030000008a2e0000d910000011010000,icedragon.io STAC2 Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||
030000008a2e0000e910000011010000,icedragon.io STAC2 Dance Pad,a:b8,b:b9,x:b10,y:b11,back:b12,platform:Linux,
|
||||
030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux,
|
||||
050000006964726f69643a636f6e0000,idroidcon 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,
|
||||
03000000b50700001503000010010000,Impact,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,
|
||||
@@ -1591,6 +1595,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006d040000d2ca000011010000,Precision 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,
|
||||
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
|
||||
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000120c0000160e000011010000,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:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000341a00003608000011010000,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,
|
||||
030000004c0500006802000010010000,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:Linux,
|
||||
030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
||||
@@ -1701,7 +1706,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
|
||||
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
||||
03000000632500002305000010010000,ShanWan 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,
|
||||
03000000632500002605000010010000,ShanWan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1858,4 +1862,5 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000120c0000100e000011010000,Zeroplus P4,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,
|
||||
03000000120c0000101e000011010000,Zeroplus P4,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,
|
||||
03000000120c0000182e000011010000,Zeroplus PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000790000002201000011010000,ZhiXu GuliKit D,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,
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ void DisplaySurface::handleCloseEvent(QCloseEvent* event)
|
||||
// In the latter case, it's going to destroy us, so don't let Qt do it first.
|
||||
// Treat a close event while fullscreen as an exit, that way ALT+F4 closes PCSX2,
|
||||
// rather than just the game.
|
||||
if (QtHost::IsVMValid() && !isActuallyFullscreen())
|
||||
if (QtHost::IsVMValid() && !isFullScreen())
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true),
|
||||
Q_ARG(bool, true), Q_ARG(bool, false));
|
||||
@@ -147,10 +147,44 @@ void DisplaySurface::handleCloseEvent(QCloseEvent* event)
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
bool DisplaySurface::isActuallyFullscreen() const
|
||||
bool DisplaySurface::isFullScreen() const
|
||||
{
|
||||
// DisplaySurface is always in a container, so we need to check parent window
|
||||
return parent()->windowState() & Qt::WindowFullScreen;
|
||||
// DisplaySurface may be in a container
|
||||
return (parent() ? parent()->windowState() : windowState()) & Qt::WindowFullScreen;
|
||||
}
|
||||
|
||||
void DisplaySurface::setFocus()
|
||||
{
|
||||
if (m_container)
|
||||
m_container->setFocus();
|
||||
else
|
||||
requestActivate();
|
||||
}
|
||||
|
||||
QByteArray DisplaySurface::saveGeometry() const
|
||||
{
|
||||
if (m_container)
|
||||
return m_container->saveGeometry();
|
||||
else
|
||||
{
|
||||
// QWindow lacks saveGeometry, so create a dummy widget and copy geometry across.
|
||||
QWidget dummy = QWidget();
|
||||
dummy.setGeometry(geometry());
|
||||
return dummy.saveGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void DisplaySurface::restoreGeometry(const QByteArray& geometry)
|
||||
{
|
||||
if (m_container)
|
||||
m_container->restoreGeometry(geometry);
|
||||
else
|
||||
{
|
||||
// QWindow lacks restoreGeometry, so create a dummy widget and copy geometry across.
|
||||
QWidget dummy = QWidget();
|
||||
dummy.restoreGeometry(geometry);
|
||||
setGeometry(dummy.geometry());
|
||||
}
|
||||
}
|
||||
|
||||
void DisplaySurface::updateCenterPos()
|
||||
@@ -393,10 +427,18 @@ bool DisplaySurface::event(QEvent* event)
|
||||
return event->isAccepted();
|
||||
|
||||
case QEvent::Move:
|
||||
{
|
||||
updateCenterPos();
|
||||
return true;
|
||||
}
|
||||
|
||||
// These events only work on the top level control.
|
||||
// Which is this container when render to seperate or fullscreen is active (Windows).
|
||||
case QEvent::Close:
|
||||
handleCloseEvent(static_cast<QCloseEvent*>(event));
|
||||
return true;
|
||||
case QEvent::WindowStateChange:
|
||||
if (static_cast<QWindowStateChangeEvent*>(event)->oldState() & Qt::WindowMinimized)
|
||||
emit windowRestoredEvent();
|
||||
return false;
|
||||
|
||||
default:
|
||||
return QWindow::event(event);
|
||||
@@ -418,7 +460,7 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
|
||||
return true;
|
||||
|
||||
// These events only work on the top level control.
|
||||
// Which is this container when render to seperate or fullscreen is active.
|
||||
// Which is this container when render to seperate or fullscreen is active (Non-Windows).
|
||||
case QEvent::Close:
|
||||
handleCloseEvent(static_cast<QCloseEvent*>(event));
|
||||
return true;
|
||||
@@ -427,8 +469,8 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
|
||||
emit windowRestoredEvent();
|
||||
return false;
|
||||
|
||||
case QEvent::ChildRemoved:
|
||||
if (static_cast<QChildEvent*>(event)->child() == m_container)
|
||||
case QEvent::ChildWindowRemoved:
|
||||
if (static_cast<QChildWindowEvent*>(event)->child() == this)
|
||||
{
|
||||
object->removeEventFilter(this);
|
||||
m_container = nullptr;
|
||||
|
||||
@@ -30,6 +30,12 @@ public:
|
||||
void updateRelativeMode(bool enabled);
|
||||
void updateCursor(bool hidden);
|
||||
|
||||
bool isFullScreen() const;
|
||||
void setFocus();
|
||||
|
||||
QByteArray saveGeometry() const;
|
||||
void restoreGeometry(const QByteArray& geometry);
|
||||
|
||||
Q_SIGNALS:
|
||||
void windowResizedEvent(int width, int height, float scale);
|
||||
void windowRestoredEvent();
|
||||
@@ -47,7 +53,6 @@ private Q_SLOTS:
|
||||
void onResizeDebounceTimer();
|
||||
|
||||
private:
|
||||
bool isActuallyFullscreen() const;
|
||||
void updateCenterPos();
|
||||
|
||||
QPoint m_relative_mouse_start_pos{};
|
||||
|
||||
@@ -100,6 +100,13 @@ static quint32 s_current_running_crc;
|
||||
static bool s_record_on_start = false;
|
||||
static QString s_path_to_recording_for_record_on_start;
|
||||
|
||||
// DX cannot fullscreen when the display surface is in a container.
|
||||
// QWindow, however, seems to lack CSD under wayland, so needs the container.
|
||||
// MAC is unknown
|
||||
#ifdef _WIN32
|
||||
#define DISPLAY_SURFACE_WINDOW
|
||||
#endif
|
||||
|
||||
MainWindow::MainWindow()
|
||||
{
|
||||
pxAssert(!g_main_window);
|
||||
@@ -1008,10 +1015,15 @@ void MainWindow::updateWindowTitle()
|
||||
if (windowTitle() != main_title)
|
||||
setWindowTitle(main_title);
|
||||
|
||||
if (m_display_container && !isRenderingToMain())
|
||||
if (m_display_surface && !isRenderingToMain())
|
||||
{
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
if (m_display_surface->title() != display_title)
|
||||
m_display_surface->setTitle(display_title);
|
||||
#else
|
||||
if (m_display_container->windowTitle() != display_title)
|
||||
m_display_container->setWindowTitle(display_title);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (g_log_window)
|
||||
@@ -1040,7 +1052,13 @@ void MainWindow::updateWindowState(bool force_visible)
|
||||
|
||||
// Update the display widget too if rendering separately.
|
||||
if (m_display_surface && !isRenderingToMain())
|
||||
{
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
QtUtils::SetWindowResizeable(m_display_surface, resizeable);
|
||||
#else
|
||||
QtUtils::SetWindowResizeable(m_display_container, resizeable);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setProgressBar(int current, int total)
|
||||
@@ -1075,12 +1093,12 @@ bool MainWindow::isRenderingFullscreen() const
|
||||
if (!MTGS::IsOpen() || !m_display_surface)
|
||||
return false;
|
||||
|
||||
return m_display_container->isFullScreen();
|
||||
return m_display_surface->isFullScreen();
|
||||
}
|
||||
|
||||
bool MainWindow::isRenderingToMain() const
|
||||
{
|
||||
return (m_display_surface && m_ui.mainContainer->indexOf(m_display_container) == 1);
|
||||
return (m_display_container && m_ui.mainContainer->indexOf(m_display_container) == 1);
|
||||
}
|
||||
|
||||
bool MainWindow::shouldHideMouseCursor() const
|
||||
@@ -1108,16 +1126,25 @@ bool MainWindow::shouldMouseLock() const
|
||||
if (m_display_created == false || m_display_surface == nullptr)
|
||||
return false;
|
||||
|
||||
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
|
||||
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
|
||||
(!m_settings_window || m_settings_window->isHidden());
|
||||
const bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
|
||||
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
|
||||
(!m_settings_window || m_settings_window->isHidden());
|
||||
|
||||
auto* displayWindow = isRenderingToMain() ? window() : m_display_container->window();
|
||||
|
||||
if (displayWindow == nullptr)
|
||||
if (!windowsHidden)
|
||||
return false;
|
||||
|
||||
return windowsHidden && (displayWindow->isActiveWindow() || displayWindow->isFullScreen());
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
if (isRenderingToMain())
|
||||
{
|
||||
const auto* displayWindow = window();
|
||||
return displayWindow ? (displayWindow->isActiveWindow() || displayWindow->isFullScreen()) : false;
|
||||
}
|
||||
else
|
||||
return m_display_surface->isActive() || m_display_surface->isFullScreen();
|
||||
#else
|
||||
const auto* displayWindow = isRenderingToMain() ? window() : m_display_container->window();
|
||||
return displayWindow ? (displayWindow->isActiveWindow() || displayWindow->isFullScreen()) : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MainWindow::shouldAbortForMemcardBusy(const VMLock& lock)
|
||||
@@ -1180,7 +1207,7 @@ void MainWindow::switchToEmulationView()
|
||||
g_emu_thread->setVMPaused(false);
|
||||
|
||||
if (m_display_surface)
|
||||
m_display_container->setFocus();
|
||||
m_display_surface->setFocus();
|
||||
}
|
||||
|
||||
void MainWindow::refreshGameList(bool invalidate_cache, bool popup_on_error)
|
||||
@@ -2129,7 +2156,7 @@ void MainWindow::onVMResumed()
|
||||
if (m_display_surface)
|
||||
{
|
||||
updateDisplayWidgetCursor();
|
||||
m_display_container->setFocus();
|
||||
m_display_surface->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2449,21 +2476,25 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
|
||||
if (!is_fullscreen && !is_rendering_to_main)
|
||||
saveDisplayWindowGeometryToConfig();
|
||||
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
auto* displayWindow = m_display_surface;
|
||||
#else
|
||||
auto* displayWindow = m_display_container;
|
||||
#endif
|
||||
if (fullscreen)
|
||||
{
|
||||
m_display_container->showFullScreen();
|
||||
}
|
||||
displayWindow->showFullScreen();
|
||||
else
|
||||
{
|
||||
// Needs to exit fullscreen before resizing
|
||||
displayWindow->showNormal();
|
||||
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
|
||||
m_display_container->setGeometry(geometry());
|
||||
displayWindow->setGeometry(geometry());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
m_display_container->showNormal();
|
||||
}
|
||||
|
||||
updateDisplayWidgetCursor();
|
||||
m_display_container->setFocus();
|
||||
m_display_surface->setFocus();
|
||||
updateWindowState();
|
||||
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
@@ -2500,7 +2531,7 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
|
||||
updateWindowState();
|
||||
|
||||
updateDisplayWidgetCursor();
|
||||
m_display_container->setFocus();
|
||||
m_display_surface->setFocus();
|
||||
return wi;
|
||||
}
|
||||
|
||||
@@ -2517,9 +2548,14 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
|
||||
m_display_surface = new DisplaySurface();
|
||||
if (fullscreen || !render_to_main)
|
||||
{
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
m_display_surface->setTitle(windowTitle());
|
||||
m_display_surface->setIcon(windowIcon());
|
||||
#else
|
||||
m_display_container = m_display_surface->createWindowContainer();
|
||||
m_display_container->setWindowTitle(windowTitle());
|
||||
m_display_container->setWindowIcon(windowIcon());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2528,20 +2564,38 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
// On Wayland, while move/restoreGeometry can't position the window, it can influence which screen they show up on
|
||||
// On Wayland, while move/restoreGeometry can't position the window, it can influence which screen they show up on.
|
||||
// Other platforms can position windows fine, but the only thing that matters here is the screen.
|
||||
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
if (isVisible() && g_emu_thread->shouldRenderToMain())
|
||||
m_display_surface->setFramePosition(pos());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
m_display_surface->showFullScreen();
|
||||
#else
|
||||
if (isVisible() && g_emu_thread->shouldRenderToMain())
|
||||
m_display_container->move(pos());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
m_display_container->showFullScreen();
|
||||
#endif
|
||||
}
|
||||
else if (!render_to_main)
|
||||
{
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
|
||||
m_display_surface->setGeometry(geometry());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
m_display_surface->showNormal();
|
||||
#else
|
||||
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
|
||||
m_display_container->setGeometry(geometry());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
m_display_container->showNormal();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2570,12 +2624,21 @@ void MainWindow::displayResizeRequested(qint32 width, qint32 height)
|
||||
width = static_cast<qint32>(std::max(static_cast<int>(std::lroundf(static_cast<float>(width) / dpr)), 1));
|
||||
height = static_cast<qint32>(std::max(static_cast<int>(std::lroundf(static_cast<float>(height) / dpr)), 1));
|
||||
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
if (!m_display_container)
|
||||
{
|
||||
// no parent - rendering to separate window. easy.
|
||||
QtUtils::ResizePotentiallyFixedSizeWindow(m_display_surface, width, height);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!m_display_container->parent())
|
||||
{
|
||||
// no parent - rendering to separate window. easy.
|
||||
QtUtils::ResizePotentiallyFixedSizeWindow(m_display_container, width, height);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// we are rendering to the main window. we have to add in the extra height from the toolbar/status bar.
|
||||
const s32 extra_height = this->height() - m_display_container->height();
|
||||
@@ -2608,7 +2671,7 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
|
||||
if (!m_display_surface)
|
||||
return;
|
||||
|
||||
if (!isRenderingFullscreen() && !isRenderingToMain())
|
||||
if (!m_display_surface->isFullScreen() && !isRenderingToMain())
|
||||
saveDisplayWindowGeometryToConfig();
|
||||
|
||||
if (isRenderingToMain())
|
||||
@@ -2622,12 +2685,18 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
|
||||
}
|
||||
}
|
||||
|
||||
// displau surface is always in a container
|
||||
pxAssert(m_display_container != nullptr);
|
||||
m_display_container->deleteLater();
|
||||
m_display_container = nullptr;
|
||||
// m_display_surface will be destroyed by the container's dtor
|
||||
m_display_surface = nullptr;
|
||||
if (m_display_container)
|
||||
{
|
||||
m_display_container->deleteLater();
|
||||
m_display_container = nullptr;
|
||||
// m_display_surface will be destroyed by the container's dtor
|
||||
m_display_surface = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_display_surface->deleteLater();
|
||||
m_display_surface = nullptr;
|
||||
}
|
||||
|
||||
updateDisplayRelatedActions(false, false, false);
|
||||
}
|
||||
@@ -2639,14 +2708,6 @@ void MainWindow::updateDisplayWidgetCursor()
|
||||
m_display_surface->updateCursor(s_vm_valid && !s_vm_paused && shouldHideMouseCursor());
|
||||
}
|
||||
|
||||
void MainWindow::focusDisplayWidget()
|
||||
{
|
||||
if (!m_display_surface || centralWidget() != m_display_container)
|
||||
return;
|
||||
|
||||
m_display_container->setFocus();
|
||||
}
|
||||
|
||||
void MainWindow::setupMouseMoveHandler()
|
||||
{
|
||||
auto mouse_cb_fn = [](int x, int y) {
|
||||
@@ -2677,7 +2738,11 @@ void MainWindow::checkMousePosition(int x, int y)
|
||||
|
||||
// logical (DIP) frame rect
|
||||
const QSize logicalSize = displayWindow->size();
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
const QPoint logicalPosition = isRenderingToMain() ? (displayWindow->position() + displayWindow->parent()->position()) : displayWindow->position();
|
||||
#else
|
||||
const QPoint logicalPosition = displayWindow->position() + displayWindow->parent()->position();
|
||||
#endif
|
||||
|
||||
// The offset to the origin of the current screen is in device-independent pixels while the origin itself is native!
|
||||
// The logicalPosition is the sum of these two values, so we need to separate them and only scale the offset
|
||||
@@ -2708,13 +2773,13 @@ void MainWindow::checkMousePosition(int x, int y)
|
||||
|
||||
void MainWindow::saveDisplayWindowGeometryToConfig()
|
||||
{
|
||||
if (m_display_container->windowState() & Qt::WindowFullScreen)
|
||||
if (m_display_surface->isFullScreen())
|
||||
{
|
||||
// if we somehow ended up here, don't save the fullscreen state to the config
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray geometry = m_display_container->saveGeometry();
|
||||
const QByteArray geometry = m_display_surface->saveGeometry();
|
||||
const QByteArray geometry_b64 = geometry.toBase64();
|
||||
const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "DisplayWindowGeometry");
|
||||
if (old_geometry_b64 != geometry_b64.constData())
|
||||
@@ -2730,15 +2795,23 @@ void MainWindow::restoreDisplayWindowGeometryFromConfig()
|
||||
const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64));
|
||||
if (!geometry.isEmpty())
|
||||
{
|
||||
m_display_container->restoreGeometry(geometry);
|
||||
m_display_surface->restoreGeometry(geometry);
|
||||
|
||||
// make sure we're not loading a dodgy config which had fullscreen set...
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
m_display_surface->setWindowStates(m_display_surface->windowStates() & ~(Qt::WindowFullScreen | Qt::WindowActive));
|
||||
#else
|
||||
m_display_container->setWindowState(m_display_container->windowState() & ~(Qt::WindowFullScreen | Qt::WindowActive));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// default size
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
m_display_surface->resize(640, 480);
|
||||
#else
|
||||
m_display_container->resize(640, 480);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3308,7 +3381,7 @@ MainWindow::VMLock MainWindow::pauseAndLockVM()
|
||||
g_emu_thread->setFullscreen(false, false);
|
||||
|
||||
// Process events untill both EmuThread and Qt have finished exiting fullscreen
|
||||
while (QtHost::IsVMValid() && (g_emu_thread->isFullscreen() || m_display_container->isFullScreen()))
|
||||
while (QtHost::IsVMValid() && (g_emu_thread->isFullscreen() || m_display_surface->isFullScreen()))
|
||||
{
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
}
|
||||
@@ -3320,7 +3393,27 @@ MainWindow::VMLock MainWindow::pauseAndLockVM()
|
||||
g_main_window->raise();
|
||||
g_main_window->activateWindow();
|
||||
|
||||
return VMLock(m_display_container, was_paused, was_fullscreen);
|
||||
#ifdef DISPLAY_SURFACE_WINDOW
|
||||
if (!m_display_container)
|
||||
{
|
||||
// Create a temporary parent for the dialog.
|
||||
QWidget* dialog_parent = new QWidget();
|
||||
dialog_parent->setAttribute(Qt::WA_NativeWindow);
|
||||
QWindow* window_handle = dialog_parent->windowHandle();
|
||||
|
||||
// Set the transient parent to the display surface.
|
||||
// This will position the dialog_parent over the display surface (and thus so will any dialogs)
|
||||
// and also enforces the focus lock of modal dialogs against the display surface.
|
||||
// This works even without showing the dialog_parent window.
|
||||
window_handle->setTransientParent(m_display_surface);
|
||||
|
||||
return VMLock(dialog_parent, was_paused, was_fullscreen, true);
|
||||
}
|
||||
else
|
||||
return VMLock(m_display_container, was_paused, was_fullscreen, false);
|
||||
#else
|
||||
return VMLock(m_display_container, was_paused, was_fullscreen, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::rescanFile(const std::string& path)
|
||||
@@ -3328,11 +3421,12 @@ void MainWindow::rescanFile(const std::string& path)
|
||||
m_game_list_widget->rescanFile(path);
|
||||
}
|
||||
|
||||
MainWindow::VMLock::VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen)
|
||||
MainWindow::VMLock::VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen, bool owns_parent)
|
||||
: m_dialog_parent(dialog_parent)
|
||||
, m_has_lock(true)
|
||||
, m_was_paused(was_paused)
|
||||
, m_was_fullscreen(was_fullscreen)
|
||||
, m_owns_dialog_parent(owns_parent)
|
||||
{
|
||||
QtHost::LockVMWithDialog();
|
||||
}
|
||||
@@ -3342,11 +3436,13 @@ MainWindow::VMLock::VMLock(VMLock&& lock)
|
||||
, m_has_lock(lock.m_has_lock)
|
||||
, m_was_paused(lock.m_was_paused)
|
||||
, m_was_fullscreen(lock.m_was_fullscreen)
|
||||
, m_owns_dialog_parent(lock.m_owns_dialog_parent)
|
||||
{
|
||||
lock.m_dialog_parent = nullptr;
|
||||
lock.m_has_lock = false;
|
||||
lock.m_was_paused = true;
|
||||
lock.m_was_fullscreen = false;
|
||||
lock.m_owns_dialog_parent = false;
|
||||
}
|
||||
|
||||
MainWindow::VMLock::~VMLock()
|
||||
@@ -3354,6 +3450,12 @@ MainWindow::VMLock::~VMLock()
|
||||
if (m_has_lock)
|
||||
QtHost::UnlockVMWithDialog();
|
||||
|
||||
if (m_owns_dialog_parent && m_dialog_parent)
|
||||
{
|
||||
m_dialog_parent->deleteLater();
|
||||
m_dialog_parent = nullptr;
|
||||
}
|
||||
|
||||
if (m_was_fullscreen)
|
||||
{
|
||||
g_main_window->m_is_temporarily_windowed = false;
|
||||
|
||||
@@ -65,13 +65,14 @@ public:
|
||||
void cancelResume();
|
||||
|
||||
private:
|
||||
VMLock(QWidget* dialog_parent, bool was_paused, bool was_exclusive_fullscreen);
|
||||
VMLock(QWidget* dialog_parent, bool was_paused, bool was_exclusive_fullscreen, bool owns_parent);
|
||||
friend MainWindow;
|
||||
|
||||
QWidget* m_dialog_parent;
|
||||
bool m_has_lock;
|
||||
bool m_was_paused;
|
||||
bool m_was_fullscreen;
|
||||
bool m_owns_dialog_parent;
|
||||
};
|
||||
|
||||
/// Default filter for opening a file.
|
||||
@@ -138,7 +139,6 @@ private Q_SLOTS:
|
||||
void displayResizeRequested(qint32 width, qint32 height);
|
||||
void mouseModeRequested(bool relative_mode, bool hide_cursor);
|
||||
void releaseRenderWindow();
|
||||
void focusDisplayWidget();
|
||||
void setupMouseMoveHandler();
|
||||
void onGameListRefreshComplete();
|
||||
void onGameListRefreshProgress(const QString& status, int current, int total);
|
||||
|
||||
@@ -366,6 +366,25 @@ namespace QtUtils
|
||||
}
|
||||
}
|
||||
|
||||
void SetWindowResizeable(QWindow* window, bool resizeable)
|
||||
{
|
||||
if (resizeable)
|
||||
{
|
||||
// Min/max numbers come from uic.
|
||||
window->setMinimumWidth(1);
|
||||
window->setMinimumHeight(1);
|
||||
window->setMaximumWidth(16777215);
|
||||
window->setMaximumHeight(16777215);
|
||||
}
|
||||
else
|
||||
{
|
||||
window->setMinimumWidth(window->width());
|
||||
window->setMinimumHeight(window->height());
|
||||
window->setMaximumWidth(window->width());
|
||||
window->setMaximumHeight(window->height());
|
||||
}
|
||||
}
|
||||
|
||||
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height)
|
||||
{
|
||||
width = std::max(width, 1);
|
||||
@@ -376,6 +395,22 @@ namespace QtUtils
|
||||
widget->resize(width, height);
|
||||
}
|
||||
|
||||
void ResizePotentiallyFixedSizeWindow(QWindow* window, int width, int height)
|
||||
{
|
||||
width = std::max(width, 1);
|
||||
height = std::max(height, 1);
|
||||
|
||||
if (window->minimumHeight() == window->maximumHeight())
|
||||
{
|
||||
window->setMinimumWidth(width);
|
||||
window->setMinimumHeight(height);
|
||||
window->setMaximumWidth(width);
|
||||
window->setMaximumHeight(height);
|
||||
}
|
||||
|
||||
window->resize(width, height);
|
||||
}
|
||||
|
||||
QString AbstractItemModelToCSV(QAbstractItemModel* model, int role, bool useQuotes)
|
||||
{
|
||||
QString csv;
|
||||
|
||||
@@ -102,9 +102,11 @@ namespace QtUtils
|
||||
|
||||
/// Changes whether a window is resizable.
|
||||
void SetWindowResizeable(QWidget* widget, bool resizeable);
|
||||
void SetWindowResizeable(QWindow* window, bool resizeable);
|
||||
|
||||
/// Adjusts the fixed size for a window if it's not resizeable.
|
||||
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height);
|
||||
void ResizePotentiallyFixedSizeWindow(QWindow* window, int width, int height);
|
||||
|
||||
/// Returns the common window info structure for a Qt Window/Widget.
|
||||
template <class T>
|
||||
|
||||
@@ -17,7 +17,8 @@ AchievementLoginDialog::AchievementLoginDialog(QWidget* parent, Achievements::Lo
|
||||
, m_reason(reason)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
QtUtils::SetScalableIcon(m_ui.loginIcon, QIcon::fromTheme(QStringLiteral("login-box-line")), QSize(32, 32));
|
||||
const QString base_path(QtHost::GetResourcesBasePath());
|
||||
QtUtils::SetScalableIcon(m_ui.loginIcon, QIcon(QStringLiteral("%1/icons/ra-icon.svg").arg(base_path)), QSize(50, 50));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
// Adjust text if needed based on reason.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "common/HeterogeneousContainers.h"
|
||||
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QStandardItemModel>
|
||||
|
||||
GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent)
|
||||
@@ -40,6 +41,9 @@ GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* settings_dialog
|
||||
|
||||
m_ui.cheatList->expandAll();
|
||||
|
||||
m_ui.cheatList->viewport()->installEventFilter(this);
|
||||
m_ui.cheatList->viewport()->setMouseTracking(true);
|
||||
|
||||
SettingsInterface* sif = dialog()->getSettingsInterface();
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCheats, "EmuCore", "EnableCheats", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.allCRCsCheckbox, "EmuCore", "ShowCheatsForAllCRCs", false);
|
||||
@@ -83,7 +87,7 @@ void GameCheatSettingsWidget::onCheatListItemDoubleClicked(const QModelIndex& in
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant data = item->data(Qt::UserRole);
|
||||
QVariant data = item->data(NAME_ROLE);
|
||||
if (!data.isValid())
|
||||
return;
|
||||
|
||||
@@ -95,7 +99,7 @@ void GameCheatSettingsWidget::onCheatListItemDoubleClicked(const QModelIndex& in
|
||||
|
||||
void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
|
||||
{
|
||||
QVariant data = item->data(Qt::UserRole);
|
||||
QVariant data = item->data(NAME_ROLE);
|
||||
if (!data.isValid())
|
||||
return;
|
||||
|
||||
@@ -109,6 +113,31 @@ void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
|
||||
setCheatEnabled(std::move(cheat_name), current_checked, true);
|
||||
}
|
||||
|
||||
void GameCheatSettingsWidget::onCheatListItemHovered(const QModelIndex& index)
|
||||
{
|
||||
const QModelIndex source_index = m_model_proxy->mapToSource(index);
|
||||
const QModelIndex sibling_index = source_index.siblingAtColumn(0);
|
||||
QStandardItem* item = m_model->itemFromIndex(sibling_index);
|
||||
if (!item)
|
||||
{
|
||||
// No item is selected.
|
||||
m_ui.appliedLabel->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<Patch::patch_place_type> place;
|
||||
|
||||
bool ok;
|
||||
int place_value = item->data(PLACE_ROLE).toInt(&ok);
|
||||
if (ok)
|
||||
{
|
||||
// The patch commands in the group are all applied at the same time.
|
||||
place = static_cast<Patch::patch_place_type>(place_value);
|
||||
}
|
||||
|
||||
m_ui.appliedLabel->setText(tr("<strong>Applied:</strong> %1").arg(Patch::PlaceToString(place)));
|
||||
}
|
||||
|
||||
void GameCheatSettingsWidget::onReloadClicked()
|
||||
{
|
||||
reloadList();
|
||||
@@ -136,6 +165,32 @@ void GameCheatSettingsWidget::disableAllCheats()
|
||||
si->Save();
|
||||
}
|
||||
|
||||
bool GameCheatSettingsWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
if (watched == m_ui.cheatList->viewport())
|
||||
{
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
|
||||
onCheatListItemHovered(m_ui.cheatList->indexAt(mouse_event->position().toPoint()));
|
||||
return true;
|
||||
}
|
||||
case QEvent::Leave:
|
||||
{
|
||||
onCheatListItemHovered(QModelIndex());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SettingsWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void GameCheatSettingsWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
@@ -185,7 +240,7 @@ void GameCheatSettingsWidget::setStateRecursively(QStandardItem* parent, bool en
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
QStandardItem* item = parent ? parent->child(i, 0) : m_model->item(i, 0);
|
||||
QVariant data = item->data(Qt::UserRole);
|
||||
QVariant data = item->data(NAME_ROLE);
|
||||
if (data.isValid())
|
||||
{
|
||||
if ((item->checkState() == Qt::Checked) != enabled)
|
||||
@@ -277,7 +332,9 @@ QList<QStandardItem*> GameCheatSettingsWidget::populateTreeViewRow(const Patch::
|
||||
const std::string_view name_part = pi.GetNamePart();
|
||||
nameItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren | Qt::ItemIsEnabled);
|
||||
nameItem->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
|
||||
nameItem->setData(QString::fromStdString(pi.name), Qt::UserRole);
|
||||
nameItem->setData(QString::fromStdString(pi.name), NAME_ROLE);
|
||||
if (pi.place.has_value())
|
||||
nameItem->setData(static_cast<int>(*pi.place), PLACE_ROLE);
|
||||
if (!name_part.empty())
|
||||
nameItem->setText(QString::fromUtf8(name_part.data(), name_part.length()));
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
~GameCheatSettingsWidget();
|
||||
|
||||
void disableAllCheats();
|
||||
bool eventFilter(QObject* watched, QEvent* event) override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
@@ -39,6 +40,7 @@ protected:
|
||||
private Q_SLOTS:
|
||||
void onCheatListItemDoubleClicked(const QModelIndex& index);
|
||||
void onCheatListItemChanged(QStandardItem* item);
|
||||
void onCheatListItemHovered(const QModelIndex& index);
|
||||
void onReloadClicked();
|
||||
void updateListEnabled();
|
||||
void reloadList();
|
||||
@@ -50,6 +52,12 @@ private:
|
||||
void setStateForAll(bool enabled);
|
||||
void setStateRecursively(QStandardItem* parent, bool enabled);
|
||||
|
||||
enum Roles
|
||||
{
|
||||
NAME_ROLE = Qt::UserRole,
|
||||
PLACE_ROLE = Qt::UserRole + 1
|
||||
};
|
||||
|
||||
Ui::GameCheatSettingsWidget m_ui;
|
||||
QStandardItemModel* m_model = nullptr;
|
||||
QSortFilterProxyModel* m_model_proxy = nullptr;
|
||||
|
||||
@@ -90,6 +90,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="appliedLabel">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -165,11 +165,12 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
|
||||
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
|
||||
if (enable_debug_layer)
|
||||
{
|
||||
ComPtr<ID3D12Debug> debug12;
|
||||
ComPtr<ID3D12Debug1> debug12;
|
||||
hr = D3D12GetDebugInterface(IID_PPV_ARGS(debug12.put()));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
debug12->EnableDebugLayer();
|
||||
debug12->SetEnableGPUBasedValidation(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1224,8 +1225,8 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id)
|
||||
{
|
||||
//const bool isAMD = (vendor_id == 0x1002 || vendor_id == 0x1022);
|
||||
|
||||
m_features.texture_barrier = false;
|
||||
m_features.multidraw_fb_copy = GSConfig.OverrideTextureBarriers != 0;
|
||||
m_features.texture_barrier = GSConfig.OverrideTextureBarriers != 0;
|
||||
m_features.multidraw_fb_copy = false;
|
||||
m_features.broken_point_sampler = false;
|
||||
m_features.primitive_id = true;
|
||||
m_features.prefer_new_textures = true;
|
||||
@@ -3207,7 +3208,7 @@ void GSDevice12::SetStencilRef(u8 ref)
|
||||
m_dirty_flags |= DIRTY_FLAG_STENCIL_REF;
|
||||
}
|
||||
|
||||
void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state)
|
||||
void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state, bool feedback)
|
||||
{
|
||||
D3D12DescriptorHandle handle;
|
||||
if (sr)
|
||||
@@ -3225,7 +3226,7 @@ void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state)
|
||||
dtex->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
dtex->SetUseFenceCounter(GetCurrentFenceValue());
|
||||
handle = dtex->GetSRVDescriptor();
|
||||
handle = feedback ? dtex->GetFBLDescriptor() : dtex->GetSRVDescriptor();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3312,7 +3313,7 @@ void GSDevice12::UnbindTexture(GSTexture12* tex)
|
||||
{
|
||||
for (u32 i = 0; i < NUM_TOTAL_TFX_TEXTURES; i++)
|
||||
{
|
||||
if (m_tfx_textures[i] == tex->GetSRVDescriptor())
|
||||
if (m_tfx_textures[i] == tex->GetSRVDescriptor() || m_tfx_textures[i] == tex->GetFBLDescriptor())
|
||||
{
|
||||
m_tfx_textures[i] = m_null_texture->GetSRVDescriptor();
|
||||
m_dirty_flags |= DIRTY_FLAG_TFX_TEXTURES;
|
||||
@@ -3826,7 +3827,20 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
// TODO: Backport from vk.
|
||||
if (stencil_DATE_One)
|
||||
{
|
||||
config.ps.date = 0;
|
||||
config.alpha_second_pass.ps.date = 0;
|
||||
if (!config.ps.IsFeedbackLoop())
|
||||
{
|
||||
config.require_one_barrier = false;
|
||||
config.require_full_barrier = false;
|
||||
}
|
||||
if (!config.alpha_second_pass.ps.IsFeedbackLoop())
|
||||
{
|
||||
config.alpha_second_pass.require_one_barrier = false;
|
||||
config.alpha_second_pass.require_full_barrier = false;
|
||||
}
|
||||
}
|
||||
|
||||
GSTexture12* colclip_rt = static_cast<GSTexture12*>(g_gs_device->GetColorClipTexture());
|
||||
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
|
||||
@@ -3955,7 +3969,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
|
||||
// we're not drawing to the RT, so we can use it as a source
|
||||
if (config.require_one_barrier && !m_features.multidraw_fb_copy)
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
PSSetShaderResource(2, draw_rt, true);
|
||||
}
|
||||
|
||||
@@ -3985,12 +3999,24 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
m_pipeline_selector.ds = true;
|
||||
}
|
||||
|
||||
if (draw_rt && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy) || (config.tex && config.tex == config.rt)))
|
||||
const bool feedback = draw_rt && (config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier) || (config.tex && config.tex == config.rt));
|
||||
if (feedback && !m_features.texture_barrier)
|
||||
{
|
||||
// Requires a copy of the RT.
|
||||
// Used as "bind rt" flag when texture barrier is unsupported for tex is fb.
|
||||
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true));
|
||||
if (!draw_rt_clone)
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
GL_PUSH("D3D12: Copy RT to temp texture {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
EndRenderPass();
|
||||
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
if (config.require_one_barrier)
|
||||
PSSetShaderResource(2, draw_rt_clone, true);
|
||||
if (config.tex && config.tex == config.rt)
|
||||
PSSetShaderResource(0, draw_rt_clone, true);
|
||||
}
|
||||
else
|
||||
Console.Warning("D3D12: Failed to allocate temp texture for RT copy.");
|
||||
}
|
||||
|
||||
@@ -4011,8 +4037,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE :
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||
stencil_DATE ? (draw_rt_clone ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE :
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) :
|
||||
stencil_DATE ? (feedback ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE :
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) :
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
|
||||
}
|
||||
@@ -4040,7 +4066,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
UploadHWDrawVerticesAndIndices(config);
|
||||
|
||||
// now we can do the actual draw
|
||||
SendHWDraw(pipe, config, draw_rt_clone, draw_rt, config.require_one_barrier, config.require_full_barrier, false);
|
||||
SendHWDraw(pipe, config, draw_rt, feedback, config.require_one_barrier, config.require_full_barrier);
|
||||
|
||||
// blend second pass
|
||||
if (config.blend_multi_pass.enable)
|
||||
@@ -4070,15 +4096,15 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
pipe.cms = config.alpha_second_pass.colormask;
|
||||
pipe.dss = config.alpha_second_pass.depth;
|
||||
pipe.bs = config.blend;
|
||||
SendHWDraw(pipe, config, draw_rt_clone, draw_rt, config.alpha_second_pass.require_one_barrier, config.alpha_second_pass.require_full_barrier, true);
|
||||
SendHWDraw(pipe, config, draw_rt, feedback, config.alpha_second_pass.require_one_barrier, config.alpha_second_pass.require_full_barrier);
|
||||
}
|
||||
|
||||
if (draw_rt_clone)
|
||||
Recycle(draw_rt_clone);
|
||||
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
|
||||
if (draw_rt_clone)
|
||||
Recycle(draw_rt_clone);
|
||||
|
||||
// now blit the colclip texture back to the original target
|
||||
if (colclip_rt)
|
||||
{
|
||||
@@ -4113,43 +4139,45 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& config, GSTexture12* draw_rt_clone, GSTexture12* draw_rt, const bool one_barrier, const bool full_barrier, const bool skip_first_barrier)
|
||||
void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& config, GSTexture12* draw_rt, const bool feedback, const bool one_barrier, const bool full_barrier)
|
||||
{
|
||||
if (draw_rt_clone)
|
||||
if (BindDrawPipeline(pipe) && !m_features.texture_barrier) [[unlikely]]
|
||||
{
|
||||
DrawIndexedPrimitive();
|
||||
return;
|
||||
}
|
||||
|
||||
if (feedback)
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
if ((one_barrier || full_barrier) && !config.ps.IsFeedbackLoop()) [[unlikely]]
|
||||
Console.Warning("D3D12: Possible unnecessary copy detected.");
|
||||
Console.Warning("D3D12: Possible unnecessary barrier detected.");
|
||||
#endif
|
||||
auto CopyAndBind = [&](GSVector4i drawarea) {
|
||||
EndRenderPass();
|
||||
if (one_barrier || full_barrier)
|
||||
PSSetShaderResource(2, draw_rt, false, true);
|
||||
if (config.tex && config.tex == config.rt)
|
||||
PSSetShaderResource(0, draw_rt, false, true);
|
||||
|
||||
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
|
||||
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
||||
if (one_barrier || full_barrier)
|
||||
PSSetShaderResource(2, draw_rt_clone, true);
|
||||
if (config.tex && config.tex == config.rt)
|
||||
PSSetShaderResource(0, draw_rt_clone, true);
|
||||
};
|
||||
|
||||
if (m_features.multidraw_fb_copy && full_barrier)
|
||||
if (full_barrier)
|
||||
{
|
||||
pxAssert(config.drawlist && !config.drawlist->empty());
|
||||
const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
|
||||
const u32 indices_per_prim = config.indices_per_prim;
|
||||
|
||||
pxAssert(config.drawlist && !config.drawlist->empty());
|
||||
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
|
||||
GL_PUSH("Split the draw");
|
||||
g_perfmon.Put(GSPerfMon::Barriers, draw_list_size);
|
||||
|
||||
for (u32 n = 0, p = 0; n < draw_list_size; n++)
|
||||
{
|
||||
const u32 count = (*config.drawlist)[n] * indices_per_prim;
|
||||
|
||||
GSVector4i bbox = (*config.drawlist_bbox)[n].rintersect(config.drawarea);
|
||||
EndRenderPass();
|
||||
// Specify null for the after resource as both resources are used after the barrier.
|
||||
// While this may also be true before the barrier, we only write using the main resource.
|
||||
D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_ALIASING, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
barrier.Aliasing = {draw_rt->GetResource(), nullptr};
|
||||
GetCommandList()->ResourceBarrier(1, &barrier);
|
||||
|
||||
// Copy only the part needed by the draw.
|
||||
CopyAndBind(bbox);
|
||||
if (BindDrawPipeline(pipe))
|
||||
DrawIndexedPrimitive(p, count);
|
||||
p += count;
|
||||
@@ -4158,10 +4186,16 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig&
|
||||
return;
|
||||
}
|
||||
|
||||
if (one_barrier)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
|
||||
// Optimization: For alpha second pass we can reuse the copy snapshot from the first pass.
|
||||
if (!skip_first_barrier)
|
||||
CopyAndBind(config.drawarea);
|
||||
EndRenderPass();
|
||||
// Specify null for the after resource as both resources are used after the barrier.
|
||||
D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_ALIASING, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
barrier.Aliasing = {draw_rt->GetResource(), nullptr};
|
||||
GetCommandList()->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
}
|
||||
|
||||
if (BindDrawPipeline(pipe))
|
||||
|
||||
@@ -456,7 +456,7 @@ public:
|
||||
void IASetVertexBuffer(const void* vertex, size_t stride, size_t count);
|
||||
void IASetIndexBuffer(const void* index, size_t count);
|
||||
|
||||
void PSSetShaderResource(int i, GSTexture* sr, bool check_state);
|
||||
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, bool feedback = false);
|
||||
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
|
||||
|
||||
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor);
|
||||
@@ -466,7 +466,7 @@ public:
|
||||
bool BindDrawPipeline(const PipelineSelector& p);
|
||||
|
||||
void RenderHW(GSHWDrawConfig& config) override;
|
||||
void SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& config, GSTexture12* draw_rt_clone, GSTexture12* draw_rt, const bool one_barrier, const bool full_barrier, const bool skip_first_barrier);
|
||||
void SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig& config, GSTexture12* draw_rt, const bool feedback, const bool one_barrier, const bool full_barrier);
|
||||
|
||||
void UpdateHWPipelineSelector(GSHWDrawConfig& config);
|
||||
void UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config);
|
||||
|
||||
@@ -15,14 +15,17 @@
|
||||
#include "D3D12MemAlloc.h"
|
||||
|
||||
GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<D3D12MA::Allocation> allocation,
|
||||
const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor,
|
||||
const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
|
||||
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
|
||||
: m_resource(std::move(resource))
|
||||
, m_resource_fbl(std::move(resource_fbl))
|
||||
, m_allocation(std::move(allocation))
|
||||
, m_srv_descriptor(srv_descriptor)
|
||||
, m_write_descriptor(write_descriptor)
|
||||
, m_uav_descriptor(uav_descriptor)
|
||||
, m_fbl_descriptor(fbl_descriptor)
|
||||
, m_write_descriptor_type(wdtype)
|
||||
, m_dxgi_format(dxgi_format)
|
||||
, m_resource_state(resource_state)
|
||||
@@ -64,8 +67,13 @@ void GSTexture12::Destroy(bool defer)
|
||||
if (m_uav_descriptor)
|
||||
dev->DeferDescriptorDestruction(dev->GetDescriptorHeapManager(), &m_uav_descriptor);
|
||||
|
||||
if (m_fbl_descriptor)
|
||||
dev->DeferDescriptorDestruction(dev->GetDescriptorHeapManager(), &m_fbl_descriptor);
|
||||
|
||||
dev->DeferResourceDestruction(m_allocation.get(), m_resource.get());
|
||||
dev->DeferResourceDestruction(m_allocation.get(), m_resource_fbl.get());
|
||||
m_resource.reset();
|
||||
m_resource_fbl.reset();
|
||||
m_allocation.reset();
|
||||
}
|
||||
else
|
||||
@@ -88,7 +96,11 @@ void GSTexture12::Destroy(bool defer)
|
||||
if (m_uav_descriptor)
|
||||
dev->GetDescriptorHeapManager().Free(&m_uav_descriptor);
|
||||
|
||||
if (m_fbl_descriptor)
|
||||
dev->GetDescriptorHeapManager().Free(&m_fbl_descriptor);
|
||||
|
||||
m_resource.reset();
|
||||
m_resource_fbl.reset();
|
||||
m_allocation.reset();
|
||||
}
|
||||
|
||||
@@ -135,7 +147,9 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
// RT's tend to be larger, so we'll keep them committed for speed.
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||
allocationDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
||||
optimized_clear_value.Format = rtv_format;
|
||||
state = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
}
|
||||
@@ -167,20 +181,63 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource_fbl;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
HRESULT hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc, state,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
Console.Error("Create texture failed: 0x%08X", hr);
|
||||
|
||||
return {};
|
||||
if (type == Type::RenderTarget)
|
||||
{
|
||||
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo = dev->GetDevice()->GetResourceAllocationInfo(0, 1, &desc);
|
||||
|
||||
HRESULT hr = dev->GetAllocator()->AllocateMemory(&allocationDesc, &allocInfo, allocation.put());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
Console.Error("Allocate texture memory failed: 0x%08X", hr);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
hr = dev->GetAllocator()->CreateAliasingResource(allocation.get(), 0, &desc, state,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
Console.Error("Create texture resource 1 failed: 0x%08X", hr);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
hr = dev->GetAllocator()->CreateAliasingResource(allocation.get(), 0, &desc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
|
||||
IID_PPV_ARGS(resource_fbl.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
Console.Error("Create texture resource 2 failed: 0x%08X", hr);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc, state,
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// OOM isn't fatal.
|
||||
if (hr != E_OUTOFMEMORY)
|
||||
Console.Error("Create texture failed: 0x%08X", hr);
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor;
|
||||
D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor, fbl_descriptor;
|
||||
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
|
||||
if (srv_format != DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
@@ -223,9 +280,20 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
return {};
|
||||
}
|
||||
|
||||
if (resource_fbl)
|
||||
{
|
||||
if (!CreateSRVDescriptor(resource_fbl.get(), levels, srv_format, &fbl_descriptor))
|
||||
{
|
||||
dev->GetDescriptorHeapManager().Free(&uav_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<GSTexture12>(
|
||||
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(allocation),
|
||||
srv_descriptor, write_descriptor, uav_descriptor, write_descriptor_type, state));
|
||||
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
|
||||
srv_descriptor, write_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, state));
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
|
||||
@@ -272,8 +340,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
}
|
||||
|
||||
return std::unique_ptr<GSTexture12>(new GSTexture12(type, format, static_cast<u32>(desc.Width), desc.Height,
|
||||
desc.MipLevels, desc.Format, std::move(resource), {}, srv_descriptor, write_descriptor, uav_descriptor,
|
||||
write_descriptor_type, resource_state));
|
||||
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, uav_descriptor,
|
||||
{}, write_descriptor_type, resource_state));
|
||||
}
|
||||
|
||||
bool GSTexture12::CreateSRVDescriptor(
|
||||
|
||||
@@ -31,9 +31,11 @@ public:
|
||||
__fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; }
|
||||
__fi const D3D12DescriptorHandle& GetFBLDescriptor() const { return m_fbl_descriptor; }
|
||||
__fi D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; }
|
||||
__fi DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; }
|
||||
__fi ID3D12Resource* GetResource() const { return m_resource.get(); }
|
||||
__fi ID3D12Resource* GetFBLResource() const { return m_resource_fbl.get(); }
|
||||
|
||||
void* GetNativeHandle() const override;
|
||||
|
||||
@@ -68,9 +70,10 @@ private:
|
||||
};
|
||||
|
||||
GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<D3D12MA::Allocation> allocation,
|
||||
const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor,
|
||||
const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
|
||||
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
|
||||
|
||||
static bool CreateSRVDescriptor(
|
||||
ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
|
||||
@@ -83,11 +86,13 @@ private:
|
||||
void CopyTextureDataForUpload(void* dst, const void* src, u32 pitch, u32 upload_pitch, u32 height) const;
|
||||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> m_resource;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> m_resource_fbl;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation;
|
||||
|
||||
D3D12DescriptorHandle m_srv_descriptor = {};
|
||||
D3D12DescriptorHandle m_write_descriptor = {};
|
||||
D3D12DescriptorHandle m_uav_descriptor = {};
|
||||
D3D12DescriptorHandle m_fbl_descriptor = {};
|
||||
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;
|
||||
|
||||
DXGI_FORMAT m_dxgi_format = DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
@@ -2430,6 +2430,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||
|
||||
GSTexture* primid_texture = nullptr;
|
||||
GSTexture* draw_rt_clone = nullptr;
|
||||
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
|
||||
|
||||
if (colclip_rt)
|
||||
@@ -2505,23 +2506,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
break;
|
||||
}
|
||||
|
||||
GSTexture* draw_rt_clone = nullptr;
|
||||
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
{
|
||||
// Requires a copy of the RT.
|
||||
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, colclip_rt ? GSTexture::Format::ColorClip : GSTexture::Format::Color, true);
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
GL_PUSH("GL: Copy RT to temp texture {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
CopyRect(colclip_rt ? colclip_rt : config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
}
|
||||
else
|
||||
Console.Warning("GL: Failed to allocate temp texture for RT copy.");
|
||||
}
|
||||
|
||||
IASetVertexBuffer(config.verts, config.nverts, GetVertexAlignment(config.vs.expand));
|
||||
m_vertex.start *= GetExpansionFactor(config.vs.expand);
|
||||
|
||||
@@ -2550,9 +2534,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
PSSetShaderResource(0, config.tex);
|
||||
if (config.pal)
|
||||
PSSetShaderResource(1, config.pal);
|
||||
if (draw_rt_clone)
|
||||
PSSetShaderResource(2, draw_rt_clone);
|
||||
else if (config.require_one_barrier || config.require_full_barrier)
|
||||
if (m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier))
|
||||
PSSetShaderResource(2, colclip_rt ? colclip_rt : config.rt);
|
||||
|
||||
SetupSampler(config.sampler);
|
||||
@@ -2668,6 +2650,25 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
glTextureBarrier();
|
||||
}
|
||||
|
||||
if (draw_rt && (config.require_one_barrier || (config.tex && config.tex == config.rt)) && !m_features.texture_barrier)
|
||||
{
|
||||
// Requires a copy of the RT.
|
||||
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
GL_PUSH("GL: Copy RT to temp texture {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
if (config.require_one_barrier)
|
||||
PSSetShaderResource(2, draw_rt_clone);
|
||||
if (config.tex && config.tex == config.rt)
|
||||
PSSetShaderResource(0, draw_rt_clone);
|
||||
}
|
||||
else
|
||||
Console.Warning("GL: Failed to allocate temp texture for RT copy.");
|
||||
}
|
||||
|
||||
OMSetRenderTargets(draw_rt, draw_ds, &config.scissor);
|
||||
OMSetColorMaskState(config.colormask);
|
||||
SetupOM(config.depth);
|
||||
|
||||
@@ -206,8 +206,18 @@ bool GSDeviceVK::SelectInstanceExtensions(ExtensionList* extension_list, const W
|
||||
if (enable_debug_utils && !SupportsExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false))
|
||||
Console.Warning("VK: Debug report requested, but extension is not available.");
|
||||
|
||||
oe->vk_ext_swapchain_maintenance1 = (wi.type != WindowInfo::Type::Surfaceless &&
|
||||
SupportsExtension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false));
|
||||
oe->vk_swapchain_maintenance1 = wi.type != WindowInfo::Type::Surfaceless;
|
||||
if (wi.type != WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
oe->vk_swapchain_maintenance1 = true;
|
||||
// VK_EXT_swapchain_maintenance1 requires VK_EXT_surface_maintenance1.
|
||||
// VK_KHR_swapchain_maintenance1 might require VK_KHR_surface_maintenance1 (It does on Nvidia).
|
||||
// If either VK_KHR_surface_maintenance1 is supported, or VK_EXT_swapchain_maintenance1 is unsupported, don't try VK_EXT_swapchain_maintenance1.
|
||||
oe->vk_swapchain_maintenance1_is_khr = SupportsExtension(VK_KHR_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false) ||
|
||||
!SupportsExtension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false);
|
||||
}
|
||||
else
|
||||
oe->vk_swapchain_maintenance1 = false;
|
||||
|
||||
// Needed for exclusive fullscreen control.
|
||||
SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false);
|
||||
@@ -411,6 +421,18 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
|
||||
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);
|
||||
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1)
|
||||
{
|
||||
const bool khr_swapchain_maintenance1 = SupportsExtension(VK_KHR_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false);
|
||||
// vk_swapchain_maintenance1_is_khr will be set if we havn't enabled VK_EXT_surface_maintenance1
|
||||
// This will happen if either the VK_EXT_surface_maintenance1 was unsupported, or we instead found the KHR version.
|
||||
// As the EXT version depends on the surface maintenance1 extension, we need to check that aswell.
|
||||
m_optional_extensions.vk_swapchain_maintenance1 = khr_swapchain_maintenance1 ? khr_swapchain_maintenance1 :
|
||||
(!m_optional_extensions.vk_swapchain_maintenance1_is_khr && SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false));
|
||||
|
||||
m_optional_extensions.vk_swapchain_maintenance1_is_khr = khr_swapchain_maintenance1;
|
||||
}
|
||||
|
||||
// glslang generates debug info instructions before phi nodes at the beginning of blocks when non-semantic debug info
|
||||
// is enabled, triggering errors by spirv-val. Gate it by an environment variable if you want source debugging until
|
||||
// this is fixed.
|
||||
@@ -420,10 +442,6 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
|
||||
SupportsExtension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, false);
|
||||
}
|
||||
|
||||
m_optional_extensions.vk_ext_swapchain_maintenance1 =
|
||||
m_optional_extensions.vk_ext_swapchain_maintenance1 &&
|
||||
SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false);
|
||||
|
||||
#ifdef _WIN32
|
||||
m_optional_extensions.vk_ext_full_screen_exclusive =
|
||||
enable_surface && SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false);
|
||||
@@ -611,8 +629,10 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = {
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_ext_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_khr_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR};
|
||||
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
{
|
||||
@@ -634,10 +654,18 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
attachment_feedback_loop_feature.attachmentFeedbackLoopLayout = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &attachment_feedback_loop_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_ext_swapchain_maintenance1)
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1)
|
||||
{
|
||||
swapchain_maintenance1_feature.swapchainMaintenance1 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_feature);
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1_is_khr)
|
||||
{
|
||||
swapchain_maintenance1_khr_feature.swapchainMaintenance1 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_khr_feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
swapchain_maintenance1_ext_feature.swapchainMaintenance1 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_ext_feature);
|
||||
}
|
||||
}
|
||||
|
||||
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
|
||||
@@ -704,8 +732,10 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = {
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_ext_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_TRUE};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_khr_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR, nullptr, VK_TRUE};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
|
||||
|
||||
@@ -718,8 +748,10 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
|
||||
Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature);
|
||||
if (m_optional_extensions.vk_ext_swapchain_maintenance1)
|
||||
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_feature);
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1 && m_optional_extensions.vk_swapchain_maintenance1_is_khr)
|
||||
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_khr_feature);
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1 && !m_optional_extensions.vk_swapchain_maintenance1_is_khr)
|
||||
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_ext_feature);
|
||||
|
||||
// query
|
||||
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
|
||||
@@ -794,8 +826,9 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps = false;
|
||||
}
|
||||
|
||||
m_optional_extensions.vk_ext_swapchain_maintenance1 &=
|
||||
(swapchain_maintenance1_feature.swapchainMaintenance1 == VK_TRUE);
|
||||
m_optional_extensions.vk_swapchain_maintenance1 &= m_optional_extensions.vk_swapchain_maintenance1_is_khr ?
|
||||
(swapchain_maintenance1_khr_feature.swapchainMaintenance1 == VK_TRUE) :
|
||||
(swapchain_maintenance1_ext_feature.swapchainMaintenance1 == VK_TRUE);
|
||||
|
||||
Console.WriteLn(
|
||||
"VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
|
||||
@@ -805,8 +838,9 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s",
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_swapchain_maintenance1 is %s",
|
||||
m_optional_extensions.vk_ext_swapchain_maintenance1 ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_%s_swapchain_maintenance1 is %s",
|
||||
m_optional_extensions.vk_swapchain_maintenance1_is_khr ? "KHR" : "EXT",
|
||||
m_optional_extensions.vk_swapchain_maintenance1 ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_full_screen_exclusive is %s",
|
||||
m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_KHR_driver_properties is %s",
|
||||
@@ -1266,7 +1300,8 @@ void GSDeviceVK::SubmitCommandBuffer(VKSwapChain* present_swap_chain)
|
||||
{
|
||||
// VK_ERROR_OUT_OF_DATE_KHR is not fatal, just means we need to recreate our swap chain.
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
ResizeWindow(0, 0, m_window_info.surface_scale);
|
||||
// Defer until next frame, otherwise resizing would invalidate swapchain before next present.
|
||||
m_resize_requested = true;
|
||||
else
|
||||
LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: ");
|
||||
|
||||
@@ -2183,6 +2218,8 @@ bool GSDeviceVK::UpdateWindow()
|
||||
|
||||
void GSDeviceVK::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
|
||||
{
|
||||
m_resize_requested = false;
|
||||
|
||||
if (!m_swap_chain || (m_swap_chain->GetWidth() == static_cast<u32>(new_window_width) &&
|
||||
m_swap_chain->GetHeight() == static_cast<u32>(new_window_height)))
|
||||
{
|
||||
@@ -2290,10 +2327,9 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
|
||||
VkResult res = m_swap_chain->AcquireNextImage();
|
||||
VkResult res = m_resize_requested ? VK_ERROR_OUT_OF_DATE_KHR : m_swap_chain->AcquireNextImage();
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
|
||||
m_swap_chain->ReleaseCurrentImage();
|
||||
|
||||
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
@@ -2313,6 +2349,8 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
|
||||
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
}
|
||||
else
|
||||
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
|
||||
|
||||
// This can happen when multiple resize events happen in quick succession.
|
||||
// In this case, just wait until the next frame to try again.
|
||||
@@ -5545,7 +5583,6 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config)
|
||||
|
||||
void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
|
||||
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
|
||||
GSTextureVK* draw_rt = static_cast<GSTextureVK*>(config.rt);
|
||||
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
|
||||
@@ -5678,24 +5715,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
break;
|
||||
}
|
||||
|
||||
if (config.require_one_barrier && !m_features.texture_barrier)
|
||||
{
|
||||
// requires a copy of the RT
|
||||
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, colclip_rt ? GSTexture::Format::ColorClip : GSTexture::Format::Color, true));
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
GL_PUSH("VK: Copy RT to temp texture for fbmask {%d,%d %dx%d}", config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
|
||||
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
PSSetShaderResource(2, draw_rt_clone, true);
|
||||
}
|
||||
else
|
||||
Console.Warning("VK: Failed to allocate temp texture for RT copy.");
|
||||
}
|
||||
|
||||
// Switch to colclip target for colclip hw rendering
|
||||
if (pipe.ps.colclip_hw)
|
||||
{
|
||||
@@ -5773,6 +5792,26 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
pipe.feedback_loop_flags |= m_current_framebuffer_feedback_loop;
|
||||
}
|
||||
|
||||
if (draw_rt && (config.require_one_barrier || (config.tex && config.tex == config.rt)) && !m_features.texture_barrier)
|
||||
{
|
||||
// Requires a copy of the RT.
|
||||
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true));
|
||||
if (draw_rt_clone)
|
||||
{
|
||||
GL_PUSH("VK: Copy RT to temp texture {%d,%d %dx%d}",
|
||||
config.drawarea.left, config.drawarea.top,
|
||||
config.drawarea.width(), config.drawarea.height());
|
||||
EndRenderPass();
|
||||
CopyRect(draw_rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
|
||||
if (config.require_one_barrier)
|
||||
PSSetShaderResource(2, draw_rt_clone, true);
|
||||
if (config.tex && config.tex == config.rt)
|
||||
PSSetShaderResource(0, draw_rt_clone, true);
|
||||
}
|
||||
else
|
||||
Console.Warning("VK: Failed to allocate temp texture for RT copy.");
|
||||
}
|
||||
|
||||
// We don't need the very first barrier if this is the first draw after switching to feedback loop,
|
||||
// because the layout change in itself enforces the execution dependency. colclip hw needs a barrier between
|
||||
// setup and the first draw to read it. TODO: Make colclip hw use subpasses instead.
|
||||
|
||||
@@ -41,7 +41,8 @@ public:
|
||||
bool vk_ext_rasterization_order_attachment_access : 1;
|
||||
bool vk_ext_full_screen_exclusive : 1;
|
||||
bool vk_ext_line_rasterization : 1;
|
||||
bool vk_ext_swapchain_maintenance1 : 1;
|
||||
bool vk_swapchain_maintenance1 : 1;
|
||||
bool vk_swapchain_maintenance1_is_khr : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_khr_shader_non_semantic_info : 1;
|
||||
bool vk_ext_attachment_feedback_loop_layout : 1;
|
||||
@@ -367,6 +368,7 @@ public:
|
||||
|
||||
private:
|
||||
std::unique_ptr<VKSwapChain> m_swap_chain;
|
||||
bool m_resize_requested = false;
|
||||
|
||||
VkDescriptorSetLayout m_utility_ds_layout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout m_utility_pipeline_layout = VK_NULL_HANDLE;
|
||||
|
||||
@@ -241,4 +241,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkCmdPushDescriptorSetKHR, false)
|
||||
// VK_EXT_swapchain_maintenance1
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesEXT, false)
|
||||
|
||||
// VK_KHR_swapchain_maintenance1
|
||||
VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesKHR, false)
|
||||
|
||||
#endif // VULKAN_DEVICE_ENTRY_POINT
|
||||
|
||||
@@ -366,7 +366,17 @@ bool VKSwapChain::CreateSwapChain()
|
||||
|
||||
// Store the old/current swap chain when recreating for resize
|
||||
// Old swap chain is destroyed regardless of whether the create call succeeds
|
||||
VkSwapchainKHR old_swap_chain = m_swap_chain;
|
||||
VkSwapchainKHR old_swap_chain;
|
||||
// RDNA4 experences a 2s delay in the following 2-3 vkAcquireNextImageKHR calls if we pass the old swapchain to the new one.
|
||||
// Instead, pass null. This requires us to have freed the old image, which we already do with the swapchain maintenance extension.
|
||||
if (GSDeviceVK::GetInstance()->IsDeviceAMD() && GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1)
|
||||
{
|
||||
vkDestroySwapchainKHR(GSDeviceVK::GetInstance()->GetDevice(), m_swap_chain, nullptr);
|
||||
old_swap_chain = VK_NULL_HANDLE;
|
||||
}
|
||||
else
|
||||
old_swap_chain = m_swap_chain;
|
||||
|
||||
m_swap_chain = VK_NULL_HANDLE;
|
||||
|
||||
// Now we can actually create the swap chain
|
||||
@@ -549,17 +559,29 @@ void VKSwapChain::ReleaseCurrentImage()
|
||||
return;
|
||||
|
||||
if ((m_image_acquire_result.value() == VK_SUCCESS || m_image_acquire_result.value() == VK_SUBOPTIMAL_KHR) &&
|
||||
GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_ext_swapchain_maintenance1)
|
||||
GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1)
|
||||
{
|
||||
GSDeviceVK::GetInstance()->WaitForGPUIdle();
|
||||
|
||||
const VkReleaseSwapchainImagesInfoEXT info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT,
|
||||
.swapchain = m_swap_chain,
|
||||
.imageIndexCount = 1,
|
||||
.pImageIndices = &m_current_image};
|
||||
VkResult res = vkReleaseSwapchainImagesEXT(GSDeviceVK::GetInstance()->GetDevice(), &info);
|
||||
VkResult res;
|
||||
if (GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1_is_khr)
|
||||
{
|
||||
const VkReleaseSwapchainImagesInfoKHR info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR,
|
||||
.swapchain = m_swap_chain,
|
||||
.imageIndexCount = 1,
|
||||
.pImageIndices = &m_current_image};
|
||||
res = vkReleaseSwapchainImagesKHR(GSDeviceVK::GetInstance()->GetDevice(), &info);
|
||||
}
|
||||
else
|
||||
{
|
||||
const VkReleaseSwapchainImagesInfoEXT info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT,
|
||||
.swapchain = m_swap_chain,
|
||||
.imageIndexCount = 1,
|
||||
.pImageIndices = &m_current_image};
|
||||
res = vkReleaseSwapchainImagesEXT(GSDeviceVK::GetInstance()->GetDevice(), &info);
|
||||
}
|
||||
if (res != VK_SUCCESS)
|
||||
LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImagesEXT() failed: ");
|
||||
LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImages() failed: ");
|
||||
}
|
||||
|
||||
m_image_acquire_result.reset();
|
||||
|
||||
@@ -198,10 +198,7 @@ namespace FullscreenUI
|
||||
{
|
||||
private:
|
||||
std::string m_dialogId;
|
||||
std::atomic_bool m_completed{false};
|
||||
std::atomic_bool m_success{false};
|
||||
int m_reqMiB = 0;
|
||||
std::atomic_bool m_dialogClosed{false}; // Check if dialog was already closed
|
||||
|
||||
static std::vector<std::shared_ptr<HddCreateInProgress>> s_activeOperations;
|
||||
static std::mutex s_operationsMutex;
|
||||
@@ -213,20 +210,6 @@ namespace FullscreenUI
|
||||
{
|
||||
}
|
||||
|
||||
~HddCreateInProgress()
|
||||
{
|
||||
SafeCloseDialog();
|
||||
}
|
||||
|
||||
void SafeCloseDialog()
|
||||
{
|
||||
bool expected = false;
|
||||
if (m_dialogClosed.compare_exchange_strong(expected, true))
|
||||
{
|
||||
ImGuiFullscreen::CloseProgressDialog(m_dialogId.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static bool StartCreation(const std::string& filePath, int sizeInGB, bool use48BitLBA)
|
||||
{
|
||||
if (filePath.empty() || sizeInGB <= 0)
|
||||
@@ -244,12 +227,10 @@ namespace FullscreenUI
|
||||
{
|
||||
if (!FileSystem::DeleteFilePath(filePath.c_str()))
|
||||
{
|
||||
Host::RunOnCPUThread([filePath]() {
|
||||
ShowToast(
|
||||
fmt::format("{} HDD Creation Failed", ICON_FA_TRIANGLE_EXCLAMATION),
|
||||
fmt::format("Failed to delete existing HDD image file '{}'. Please check file permissions and try again.", Path::GetFileName(filePath)),
|
||||
5.0f);
|
||||
});
|
||||
ShowToast(
|
||||
fmt::format("{} HDD Creation Failed", ICON_FA_TRIANGLE_EXCLAMATION),
|
||||
fmt::format("Failed to delete existing HDD image file '{}'. Please check file permissions and try again.", Path::GetFileName(filePath)),
|
||||
5.0f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -269,14 +250,14 @@ namespace FullscreenUI
|
||||
instance->Start();
|
||||
|
||||
if (!instance->errored)
|
||||
Host::RunOnCPUThread([size_gb = static_cast<int>(instance->neededSize / static_cast<u64>(_1gb))]() {
|
||||
MTGS::RunOnGSThread([size_gb = static_cast<int>(instance->neededSize / static_cast<u64>(_1gb))]() {
|
||||
ShowToast(
|
||||
ICON_FA_CIRCLE_CHECK,
|
||||
fmt::format("HDD image ({} GB) created successfully.", size_gb),
|
||||
3.0f);
|
||||
});
|
||||
else
|
||||
Host::RunOnCPUThread([]() {
|
||||
MTGS::RunOnGSThread([]() {
|
||||
ShowToast(
|
||||
ICON_FA_TRIANGLE_EXCLAMATION,
|
||||
"Failed to create HDD image.",
|
||||
@@ -301,10 +282,7 @@ namespace FullscreenUI
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_operationsMutex);
|
||||
for (auto& operation : s_activeOperations)
|
||||
{
|
||||
operation->SetCanceled();
|
||||
operation->SafeCloseDialog();
|
||||
}
|
||||
s_activeOperations.clear();
|
||||
}
|
||||
|
||||
@@ -323,17 +301,9 @@ namespace FullscreenUI
|
||||
ImGuiFullscreen::UpdateProgressDialog(m_dialogId.c_str(), message, 0, m_reqMiB, writtenMiB);
|
||||
}
|
||||
|
||||
virtual void SetError() override
|
||||
{
|
||||
SafeCloseDialog();
|
||||
HddCreate::SetError();
|
||||
}
|
||||
|
||||
virtual void Cleanup() override
|
||||
{
|
||||
SafeCloseDialog();
|
||||
m_success.store(!errored, std::memory_order_release);
|
||||
m_completed.store(true, std::memory_order_release);
|
||||
ImGuiFullscreen::CloseProgressDialog(m_dialogId.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -349,9 +319,7 @@ namespace FullscreenUI
|
||||
|
||||
if (sizeInGB < min_size || sizeInGB > max_size)
|
||||
{
|
||||
Host::RunOnCPUThread([min_size, max_size]() {
|
||||
ShowToast(std::string(), fmt::format("Invalid HDD size. Size must be between {} and {} GB.", min_size, max_size).c_str());
|
||||
});
|
||||
ShowToast(std::string(), fmt::format("Invalid HDD size. Size must be between {} and {} GB.", min_size, max_size).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9360,6 +9328,8 @@ TRANSLATE_NOOP("FullscreenUI", "Reset System");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?");
|
||||
TRANSLATE_NOOP("FullscreenUI", "This game has no achievements.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "This game has no leaderboards.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Game List");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Launch a game from images scanned from your game directories.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Start Game");
|
||||
@@ -9405,7 +9375,7 @@ TRANSLATE_NOOP("FullscreenUI", "Selects the color style to be used for Big Pictu
|
||||
TRANSLATE_NOOP("FullscreenUI", "When Big Picture mode is started, the game list will be displayed instead of the main menu.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Background");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Select a custom background image to use in Big Picture Mode menus.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Select a custom background image to use in Big Picture Mode menus.\n\nSupported formats: PNG, JPG, JPEG, BMP.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Removes the custom background image.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Sets the transparency of the custom background image.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Select how to display the background image.");
|
||||
@@ -9415,6 +9385,7 @@ TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a game is started.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you open the quick menu, and unpauses when you close it.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Display a modal dialog when a save state load/save operation fails.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix");
|
||||
@@ -9424,6 +9395,7 @@ TRANSLATE_NOOP("FullscreenUI", "Game Display");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Automatically switches to fullscreen mode when a game is started.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Switches between full screen and windowed when the window is double-clicked.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Hides the mouse pointer/cursor when the emulator is in fullscreen mode.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Automatically starts Big Picture Mode instead of the regular Qt interface when PCSX2 launches.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "On-Screen Display");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitors are.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "%d%%");
|
||||
@@ -9849,6 +9821,9 @@ TRANSLATE_NOOP("FullscreenUI", "Last Played: {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Size: {:.2f} MB");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to reset the play time for '{}' ({})?\n\nYour current play time is {}.\n\nThis action cannot be undone.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Backup Slot {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Slot {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State To Slot {}");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Left: ");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Top: ");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Right: ");
|
||||
@@ -9882,13 +9857,14 @@ TRANSLATE_NOOP("FullscreenUI", "AMOLED");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Fit");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Fill");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Stretch");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Center");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Tile");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Enabled");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Disabled");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Top Left");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Top Center");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Top Right");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Center Left");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Center");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Center Right");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Bottom Left");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Bottom Center");
|
||||
@@ -10108,6 +10084,7 @@ TRANSLATE_NOOP("FullscreenUI", "Pause On Start");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Pause On Menu");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Prompt On State Load/Save Failure");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
|
||||
@@ -10117,6 +10094,7 @@ TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Start Fullscreen");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Start Big Picture UI");
|
||||
TRANSLATE_NOOP("FullscreenUI", "OSD Scale");
|
||||
TRANSLATE_NOOP("FullscreenUI", "OSD Messages Position");
|
||||
TRANSLATE_NOOP("FullscreenUI", "OSD Performance Position");
|
||||
@@ -10297,7 +10275,6 @@ TRANSLATE_NOOP("FullscreenUI", "Delete Save");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Close Menu");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Default Boot");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Delete State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Full Boot");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Reset Play Time");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Confirm Reset");
|
||||
|
||||
@@ -553,7 +553,7 @@ void Patch::ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pna
|
||||
(*num_unlabelled_patches)++;
|
||||
|
||||
// Try to extract the place value of the patch lines so we can
|
||||
// display them in the GUI if they all match. TODO: Don't duplicate
|
||||
// display it in the GUI if they all match. TODO: Don't duplicate
|
||||
// all this parsing logic twice.
|
||||
if (unknown_place)
|
||||
continue;
|
||||
@@ -571,6 +571,7 @@ void Patch::ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pna
|
||||
// place values.
|
||||
current_patch.place = std::nullopt;
|
||||
unknown_place = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
current_patch.place = place;
|
||||
|
||||
@@ -1252,10 +1252,10 @@ void SaveState_ReportLoadErrorOSD(const std::string& message, std::optional<s32>
|
||||
{
|
||||
if (backup)
|
||||
full_message = fmt::format(
|
||||
TRANSLATE_FS("SaveState", "Failed to load state from slot {}: {}"), *slot, message);
|
||||
TRANSLATE_FS("SaveState", "Failed to load state from backup slot {}: {}"), *slot, message);
|
||||
else
|
||||
full_message = fmt::format(
|
||||
TRANSLATE_FS("SaveState", "Failed to load state from backup slot {}: {}"), *slot, message);
|
||||
TRANSLATE_FS("SaveState", "Failed to load state from slot {}: {}"), *slot, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user