Compare commits

...

15 Commits

Author SHA1 Message Date
PCSX2 Bot c2fd4af163 [ci skip] Qt: Update Base Translation. 2025-12-17 13:12:29 +01:00
SternXD 5bdee3a611 Qt: Add RA Logo to Achievement Login Dialog 2025-12-16 20:19:47 -05:00
TheLastRar cb026a6946 GS/DX12: Fix handling of stencil DATE one
Co-Authored-By: lightningterror <18107717+lightningterror@users.noreply.github.com>
2025-12-16 16:57:16 +01:00
TheLastRar cb5124da4b GS/DX12: Enable GBV with the debug device 2025-12-16 16:57:16 +01:00
TheLastRar 7c88af9c73 GS/DX12: Use aliasing resources for feedback 2025-12-16 16:57:16 +01:00
JordanTheToaster 465a31bbd5 GameDB: Juiced post fixes 2025-12-16 13:38:51 +01:00
TheLastRar 6deb43bde2 GS/VK: Support VK_KHR_swapchain_maintenance1
Co-Authored-By: refractionpcsx2 <6278726+refractionpcsx2@users.noreply.github.com>
2025-12-16 12:14:11 +01:00
TheLastRar 8e7dcb83a8 GS/VK: Don't reference old swapchain when recreating on AMD 2025-12-16 12:14:11 +01:00
TheLastRar 51ead1e00f GS/VK: Reduce spam when swapchain needs to be recreated 2025-12-16 12:13:12 +01:00
TheLastRar 27bcb7c29a GS/VK: Don't recreate swapchain during EndPresent 2025-12-16 12:13:12 +01:00
TheLastRar aaed4a4983 Qt: Don't contain display surface when entering fullscreen/separate on Windows 2025-12-16 12:09:06 +01:00
PCSX2 Bot 748f232976 [ci skip] Qt: Update Base Translation. 2025-12-15 19:50:06 -05:00
chaoticgd a33612cf7d Qt: Display when the hovered cheat will be applied in the UI 2025-12-15 14:20:58 -05:00
chaoticgd 5c123f3183 Patch: Fix bug causing the UI to show the wrong place value 2025-12-15 14:20:58 -05:00
PCSX2 Bot d30a7fb991 [ci skip] PAD: Update to latest controller database. 2025-12-15 19:37:04 +01:00
22 changed files with 707 additions and 304 deletions

View File

@ -13996,6 +13996,7 @@ SLED-53109:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLED-53137: SLED-53137:
name: "Stolen [Demo]" name: "Stolen [Demo]"
@ -22269,6 +22270,7 @@ SLES-53044:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLES-53045: SLES-53045:
name: "Street Racing Syndicate" name: "Street Racing Syndicate"
@ -22592,6 +22594,7 @@ SLES-53151:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLES-53152: SLES-53152:
name: "Mashed Fully Loaded" name: "Mashed Fully Loaded"
@ -32394,6 +32397,7 @@ SLKA-25283:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLKA-25284: SLKA-25284:
name: "사쿠라 대전 3 ~파리는 불타고 있는가~" name: "사쿠라 대전 3 ~파리는 불타고 있는가~"
@ -48603,6 +48607,7 @@ SLPM-66277:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLPM-66278: SLPM-66278:
name: "新・豪血寺一族 -煩悩解放-" name: "新・豪血寺一族 -煩悩解放-"
@ -68225,6 +68230,7 @@ SLUS-20872:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLUS-20873: SLUS-20873:
name: "Silent Hill 4 - The Room" name: "Silent Hill 4 - The Room"
@ -75330,6 +75336,7 @@ SLUS-29147:
cpuSpriteRenderLevel: 2 # Needed for above. cpuSpriteRenderLevel: 2 # Needed for above.
autoFlush: 1 # Fixes headlight brightness. autoFlush: 1 # Fixes headlight brightness.
cpuCLUTRender: 1 # Fixes broken headlights. cpuCLUTRender: 1 # Fixes broken headlights.
nativeScaling: 4 # Aligns post effects.
minimumBlendingLevel: 3 minimumBlendingLevel: 3
SLUS-29148: SLUS-29148:
name: "The Incredible Hulk - Ultimate Destruction [Demo]" name: "The Incredible Hulk - Ultimate Destruction [Demo]"

View File

@ -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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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,

View File

@ -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. // 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, // Treat a close event while fullscreen as an exit, that way ALT+F4 closes PCSX2,
// rather than just the game. // rather than just the game.
if (QtHost::IsVMValid() && !isActuallyFullscreen()) if (QtHost::IsVMValid() && !isFullScreen())
{ {
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true), QMetaObject::invokeMethod(g_main_window, "requestShutdown", Q_ARG(bool, true),
Q_ARG(bool, true), Q_ARG(bool, false)); Q_ARG(bool, true), Q_ARG(bool, false));
@ -147,10 +147,44 @@ void DisplaySurface::handleCloseEvent(QCloseEvent* event)
event->ignore(); event->ignore();
} }
bool DisplaySurface::isActuallyFullscreen() const bool DisplaySurface::isFullScreen() const
{ {
// DisplaySurface is always in a container, so we need to check parent window // DisplaySurface may be in a container
return parent()->windowState() & Qt::WindowFullScreen; 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() void DisplaySurface::updateCenterPos()
@ -393,10 +427,18 @@ bool DisplaySurface::event(QEvent* event)
return event->isAccepted(); return event->isAccepted();
case QEvent::Move: case QEvent::Move:
{
updateCenterPos(); updateCenterPos();
return true; 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: default:
return QWindow::event(event); return QWindow::event(event);
@ -418,7 +460,7 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
return true; return true;
// These events only work on the top level control. // 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: case QEvent::Close:
handleCloseEvent(static_cast<QCloseEvent*>(event)); handleCloseEvent(static_cast<QCloseEvent*>(event));
return true; return true;
@ -427,8 +469,8 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
emit windowRestoredEvent(); emit windowRestoredEvent();
return false; return false;
case QEvent::ChildRemoved: case QEvent::ChildWindowRemoved:
if (static_cast<QChildEvent*>(event)->child() == m_container) if (static_cast<QChildWindowEvent*>(event)->child() == this)
{ {
object->removeEventFilter(this); object->removeEventFilter(this);
m_container = nullptr; m_container = nullptr;

View File

@ -30,6 +30,12 @@ public:
void updateRelativeMode(bool enabled); void updateRelativeMode(bool enabled);
void updateCursor(bool hidden); void updateCursor(bool hidden);
bool isFullScreen() const;
void setFocus();
QByteArray saveGeometry() const;
void restoreGeometry(const QByteArray& geometry);
Q_SIGNALS: Q_SIGNALS:
void windowResizedEvent(int width, int height, float scale); void windowResizedEvent(int width, int height, float scale);
void windowRestoredEvent(); void windowRestoredEvent();
@ -47,7 +53,6 @@ private Q_SLOTS:
void onResizeDebounceTimer(); void onResizeDebounceTimer();
private: private:
bool isActuallyFullscreen() const;
void updateCenterPos(); void updateCenterPos();
QPoint m_relative_mouse_start_pos{}; QPoint m_relative_mouse_start_pos{};

View File

@ -100,6 +100,13 @@ static quint32 s_current_running_crc;
static bool s_record_on_start = false; static bool s_record_on_start = false;
static QString s_path_to_recording_for_record_on_start; 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() MainWindow::MainWindow()
{ {
pxAssert(!g_main_window); pxAssert(!g_main_window);
@ -1008,10 +1015,15 @@ void MainWindow::updateWindowTitle()
if (windowTitle() != main_title) if (windowTitle() != main_title)
setWindowTitle(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) if (m_display_container->windowTitle() != display_title)
m_display_container->setWindowTitle(display_title); m_display_container->setWindowTitle(display_title);
#endif
} }
if (g_log_window) if (g_log_window)
@ -1040,7 +1052,13 @@ void MainWindow::updateWindowState(bool force_visible)
// Update the display widget too if rendering separately. // Update the display widget too if rendering separately.
if (m_display_surface && !isRenderingToMain()) if (m_display_surface && !isRenderingToMain())
{
#ifdef DISPLAY_SURFACE_WINDOW
QtUtils::SetWindowResizeable(m_display_surface, resizeable);
#else
QtUtils::SetWindowResizeable(m_display_container, resizeable); QtUtils::SetWindowResizeable(m_display_container, resizeable);
#endif
}
} }
void MainWindow::setProgressBar(int current, int total) void MainWindow::setProgressBar(int current, int total)
@ -1075,12 +1093,12 @@ bool MainWindow::isRenderingFullscreen() const
if (!MTGS::IsOpen() || !m_display_surface) if (!MTGS::IsOpen() || !m_display_surface)
return false; return false;
return m_display_container->isFullScreen(); return m_display_surface->isFullScreen();
} }
bool MainWindow::isRenderingToMain() const 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 bool MainWindow::shouldHideMouseCursor() const
@ -1108,16 +1126,25 @@ bool MainWindow::shouldMouseLock() const
if (m_display_created == false || m_display_surface == nullptr) if (m_display_created == false || m_display_surface == nullptr)
return false; return false;
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) && const bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
(!m_controller_settings_window || m_controller_settings_window->isHidden()) && (!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
(!m_settings_window || m_settings_window->isHidden()); (!m_settings_window || m_settings_window->isHidden());
auto* displayWindow = isRenderingToMain() ? window() : m_display_container->window(); if (!windowsHidden)
if (displayWindow == nullptr)
return false; 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) bool MainWindow::shouldAbortForMemcardBusy(const VMLock& lock)
@ -1180,7 +1207,7 @@ void MainWindow::switchToEmulationView()
g_emu_thread->setVMPaused(false); g_emu_thread->setVMPaused(false);
if (m_display_surface) if (m_display_surface)
m_display_container->setFocus(); m_display_surface->setFocus();
} }
void MainWindow::refreshGameList(bool invalidate_cache, bool popup_on_error) void MainWindow::refreshGameList(bool invalidate_cache, bool popup_on_error)
@ -2129,7 +2156,7 @@ void MainWindow::onVMResumed()
if (m_display_surface) if (m_display_surface)
{ {
updateDisplayWidgetCursor(); 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) if (!is_fullscreen && !is_rendering_to_main)
saveDisplayWindowGeometryToConfig(); saveDisplayWindowGeometryToConfig();
#ifdef DISPLAY_SURFACE_WINDOW
auto* displayWindow = m_display_surface;
#else
auto* displayWindow = m_display_container;
#endif
if (fullscreen) if (fullscreen)
{ displayWindow->showFullScreen();
m_display_container->showFullScreen();
}
else else
{ {
// Needs to exit fullscreen before resizing
displayWindow->showNormal();
if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain()) if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
m_display_container->setGeometry(geometry()); displayWindow->setGeometry(geometry());
else else
restoreDisplayWindowGeometryFromConfig(); restoreDisplayWindowGeometryFromConfig();
m_display_container->showNormal();
} }
updateDisplayWidgetCursor(); updateDisplayWidgetCursor();
m_display_container->setFocus(); m_display_surface->setFocus();
updateWindowState(); updateWindowState();
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
@ -2500,7 +2531,7 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
updateWindowState(); updateWindowState();
updateDisplayWidgetCursor(); updateDisplayWidgetCursor();
m_display_container->setFocus(); m_display_surface->setFocus();
return wi; return wi;
} }
@ -2517,9 +2548,14 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
m_display_surface = new DisplaySurface(); m_display_surface = new DisplaySurface();
if (fullscreen || !render_to_main) 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 = m_display_surface->createWindowContainer();
m_display_container->setWindowTitle(windowTitle()); m_display_container->setWindowTitle(windowTitle());
m_display_container->setWindowIcon(windowIcon()); m_display_container->setWindowIcon(windowIcon());
#endif
} }
else else
{ {
@ -2528,20 +2564,38 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
if (fullscreen) 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()) if (isVisible() && g_emu_thread->shouldRenderToMain())
m_display_container->move(pos()); m_display_container->move(pos());
else else
restoreDisplayWindowGeometryFromConfig(); restoreDisplayWindowGeometryFromConfig();
m_display_container->showFullScreen(); m_display_container->showFullScreen();
#endif
} }
else if (!render_to_main) 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()) if (m_is_temporarily_windowed && g_emu_thread->shouldRenderToMain())
m_display_container->setGeometry(geometry()); m_display_container->setGeometry(geometry());
else else
restoreDisplayWindowGeometryFromConfig(); restoreDisplayWindowGeometryFromConfig();
m_display_container->showNormal(); m_display_container->showNormal();
#endif
} }
else 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)); 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)); 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()) if (!m_display_container->parent())
{ {
// no parent - rendering to separate window. easy. // no parent - rendering to separate window. easy.
QtUtils::ResizePotentiallyFixedSizeWindow(m_display_container, width, height); QtUtils::ResizePotentiallyFixedSizeWindow(m_display_container, width, height);
return; return;
} }
#endif
// we are rendering to the main window. we have to add in the extra height from the toolbar/status bar. // 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(); 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) if (!m_display_surface)
return; return;
if (!isRenderingFullscreen() && !isRenderingToMain()) if (!m_display_surface->isFullScreen() && !isRenderingToMain())
saveDisplayWindowGeometryToConfig(); saveDisplayWindowGeometryToConfig();
if (isRenderingToMain()) if (isRenderingToMain())
@ -2622,12 +2685,18 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
} }
} }
// displau surface is always in a container if (m_display_container)
pxAssert(m_display_container != nullptr); {
m_display_container->deleteLater(); m_display_container->deleteLater();
m_display_container = nullptr; m_display_container = nullptr;
// m_display_surface will be destroyed by the container's dtor // m_display_surface will be destroyed by the container's dtor
m_display_surface = nullptr; m_display_surface = nullptr;
}
else
{
m_display_surface->deleteLater();
m_display_surface = nullptr;
}
updateDisplayRelatedActions(false, false, false); updateDisplayRelatedActions(false, false, false);
} }
@ -2639,14 +2708,6 @@ void MainWindow::updateDisplayWidgetCursor()
m_display_surface->updateCursor(s_vm_valid && !s_vm_paused && shouldHideMouseCursor()); 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() void MainWindow::setupMouseMoveHandler()
{ {
auto mouse_cb_fn = [](int x, int y) { auto mouse_cb_fn = [](int x, int y) {
@ -2677,7 +2738,11 @@ void MainWindow::checkMousePosition(int x, int y)
// logical (DIP) frame rect // logical (DIP) frame rect
const QSize logicalSize = displayWindow->size(); 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(); 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 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 // 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() 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 // if we somehow ended up here, don't save the fullscreen state to the config
return; return;
} }
const QByteArray geometry = m_display_container->saveGeometry(); const QByteArray geometry = m_display_surface->saveGeometry();
const QByteArray geometry_b64 = geometry.toBase64(); const QByteArray geometry_b64 = geometry.toBase64();
const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "DisplayWindowGeometry"); const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "DisplayWindowGeometry");
if (old_geometry_b64 != geometry_b64.constData()) if (old_geometry_b64 != geometry_b64.constData())
@ -2730,15 +2795,23 @@ void MainWindow::restoreDisplayWindowGeometryFromConfig()
const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64)); const QByteArray geometry = QByteArray::fromBase64(QByteArray::fromStdString(geometry_b64));
if (!geometry.isEmpty()) 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... // 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)); m_display_container->setWindowState(m_display_container->windowState() & ~(Qt::WindowFullScreen | Qt::WindowActive));
#endif
} }
else else
{ {
// default size // default size
#ifdef DISPLAY_SURFACE_WINDOW
m_display_surface->resize(640, 480);
#else
m_display_container->resize(640, 480); m_display_container->resize(640, 480);
#endif
} }
} }
@ -3308,7 +3381,7 @@ MainWindow::VMLock MainWindow::pauseAndLockVM()
g_emu_thread->setFullscreen(false, false); g_emu_thread->setFullscreen(false, false);
// Process events untill both EmuThread and Qt have finished exiting fullscreen // 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); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} }
@ -3320,7 +3393,27 @@ MainWindow::VMLock MainWindow::pauseAndLockVM()
g_main_window->raise(); g_main_window->raise();
g_main_window->activateWindow(); 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) void MainWindow::rescanFile(const std::string& path)
@ -3328,11 +3421,12 @@ void MainWindow::rescanFile(const std::string& path)
m_game_list_widget->rescanFile(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_dialog_parent(dialog_parent)
, m_has_lock(true) , m_has_lock(true)
, m_was_paused(was_paused) , m_was_paused(was_paused)
, m_was_fullscreen(was_fullscreen) , m_was_fullscreen(was_fullscreen)
, m_owns_dialog_parent(owns_parent)
{ {
QtHost::LockVMWithDialog(); QtHost::LockVMWithDialog();
} }
@ -3342,11 +3436,13 @@ MainWindow::VMLock::VMLock(VMLock&& lock)
, m_has_lock(lock.m_has_lock) , m_has_lock(lock.m_has_lock)
, m_was_paused(lock.m_was_paused) , m_was_paused(lock.m_was_paused)
, m_was_fullscreen(lock.m_was_fullscreen) , m_was_fullscreen(lock.m_was_fullscreen)
, m_owns_dialog_parent(lock.m_owns_dialog_parent)
{ {
lock.m_dialog_parent = nullptr; lock.m_dialog_parent = nullptr;
lock.m_has_lock = false; lock.m_has_lock = false;
lock.m_was_paused = true; lock.m_was_paused = true;
lock.m_was_fullscreen = false; lock.m_was_fullscreen = false;
lock.m_owns_dialog_parent = false;
} }
MainWindow::VMLock::~VMLock() MainWindow::VMLock::~VMLock()
@ -3354,6 +3450,12 @@ MainWindow::VMLock::~VMLock()
if (m_has_lock) if (m_has_lock)
QtHost::UnlockVMWithDialog(); QtHost::UnlockVMWithDialog();
if (m_owns_dialog_parent && m_dialog_parent)
{
m_dialog_parent->deleteLater();
m_dialog_parent = nullptr;
}
if (m_was_fullscreen) if (m_was_fullscreen)
{ {
g_main_window->m_is_temporarily_windowed = false; g_main_window->m_is_temporarily_windowed = false;

View File

@ -65,13 +65,14 @@ public:
void cancelResume(); void cancelResume();
private: 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; friend MainWindow;
QWidget* m_dialog_parent; QWidget* m_dialog_parent;
bool m_has_lock; bool m_has_lock;
bool m_was_paused; bool m_was_paused;
bool m_was_fullscreen; bool m_was_fullscreen;
bool m_owns_dialog_parent;
}; };
/// Default filter for opening a file. /// Default filter for opening a file.
@ -138,7 +139,6 @@ private Q_SLOTS:
void displayResizeRequested(qint32 width, qint32 height); void displayResizeRequested(qint32 width, qint32 height);
void mouseModeRequested(bool relative_mode, bool hide_cursor); void mouseModeRequested(bool relative_mode, bool hide_cursor);
void releaseRenderWindow(); void releaseRenderWindow();
void focusDisplayWidget();
void setupMouseMoveHandler(); void setupMouseMoveHandler();
void onGameListRefreshComplete(); void onGameListRefreshComplete();
void onGameListRefreshProgress(const QString& status, int current, int total); void onGameListRefreshProgress(const QString& status, int current, int total);

View File

@ -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) void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height)
{ {
width = std::max(width, 1); width = std::max(width, 1);
@ -376,6 +395,22 @@ namespace QtUtils
widget->resize(width, height); 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 AbstractItemModelToCSV(QAbstractItemModel* model, int role, bool useQuotes)
{ {
QString csv; QString csv;

View File

@ -102,9 +102,11 @@ namespace QtUtils
/// Changes whether a window is resizable. /// Changes whether a window is resizable.
void SetWindowResizeable(QWidget* widget, bool resizeable); void SetWindowResizeable(QWidget* widget, bool resizeable);
void SetWindowResizeable(QWindow* window, bool resizeable);
/// Adjusts the fixed size for a window if it's not resizeable. /// Adjusts the fixed size for a window if it's not resizeable.
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height); 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. /// Returns the common window info structure for a Qt Window/Widget.
template <class T> template <class T>

View File

@ -17,7 +17,8 @@ AchievementLoginDialog::AchievementLoginDialog(QWidget* parent, Achievements::Lo
, m_reason(reason) , m_reason(reason)
{ {
m_ui.setupUi(this); 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); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
// Adjust text if needed based on reason. // Adjust text if needed based on reason.

View File

@ -40,6 +40,9 @@ GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* settings_dialog
m_ui.cheatList->expandAll(); m_ui.cheatList->expandAll();
m_ui.cheatList->viewport()->installEventFilter(this);
m_ui.cheatList->viewport()->setMouseTracking(true);
SettingsInterface* sif = dialog()->getSettingsInterface(); SettingsInterface* sif = dialog()->getSettingsInterface();
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCheats, "EmuCore", "EnableCheats", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCheats, "EmuCore", "EnableCheats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.allCRCsCheckbox, "EmuCore", "ShowCheatsForAllCRCs", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.allCRCsCheckbox, "EmuCore", "ShowCheatsForAllCRCs", false);
@ -83,7 +86,7 @@ void GameCheatSettingsWidget::onCheatListItemDoubleClicked(const QModelIndex& in
return; return;
} }
QVariant data = item->data(Qt::UserRole); QVariant data = item->data(NAME_ROLE);
if (!data.isValid()) if (!data.isValid())
return; return;
@ -95,7 +98,7 @@ void GameCheatSettingsWidget::onCheatListItemDoubleClicked(const QModelIndex& in
void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item) void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
{ {
QVariant data = item->data(Qt::UserRole); QVariant data = item->data(NAME_ROLE);
if (!data.isValid()) if (!data.isValid())
return; return;
@ -109,6 +112,31 @@ void GameCheatSettingsWidget::onCheatListItemChanged(QStandardItem* item)
setCheatEnabled(std::move(cheat_name), current_checked, true); 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() void GameCheatSettingsWidget::onReloadClicked()
{ {
reloadList(); reloadList();
@ -136,6 +164,32 @@ void GameCheatSettingsWidget::disableAllCheats()
si->Save(); 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) void GameCheatSettingsWidget::resizeEvent(QResizeEvent* event)
{ {
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
@ -185,7 +239,7 @@ void GameCheatSettingsWidget::setStateRecursively(QStandardItem* parent, bool en
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
QStandardItem* item = parent ? parent->child(i, 0) : m_model->item(i, 0); 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 (data.isValid())
{ {
if ((item->checkState() == Qt::Checked) != enabled) if ((item->checkState() == Qt::Checked) != enabled)
@ -277,7 +331,9 @@ QList<QStandardItem*> GameCheatSettingsWidget::populateTreeViewRow(const Patch::
const std::string_view name_part = pi.GetNamePart(); const std::string_view name_part = pi.GetNamePart();
nameItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren | Qt::ItemIsEnabled); nameItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren | Qt::ItemIsEnabled);
nameItem->setCheckState(enabled ? Qt::Checked : Qt::Unchecked); 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()) if (!name_part.empty())
nameItem->setText(QString::fromUtf8(name_part.data(), name_part.length())); nameItem->setText(QString::fromUtf8(name_part.data(), name_part.length()));

View File

@ -32,6 +32,7 @@ public:
~GameCheatSettingsWidget(); ~GameCheatSettingsWidget();
void disableAllCheats(); void disableAllCheats();
bool eventFilter(QObject* watched, QEvent* event) override;
protected: protected:
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
@ -39,6 +40,7 @@ protected:
private Q_SLOTS: private Q_SLOTS:
void onCheatListItemDoubleClicked(const QModelIndex& index); void onCheatListItemDoubleClicked(const QModelIndex& index);
void onCheatListItemChanged(QStandardItem* item); void onCheatListItemChanged(QStandardItem* item);
void onCheatListItemHovered(const QModelIndex& index);
void onReloadClicked(); void onReloadClicked();
void updateListEnabled(); void updateListEnabled();
void reloadList(); void reloadList();
@ -50,6 +52,12 @@ private:
void setStateForAll(bool enabled); void setStateForAll(bool enabled);
void setStateRecursively(QStandardItem* parent, bool enabled); void setStateRecursively(QStandardItem* parent, bool enabled);
enum Roles
{
NAME_ROLE = Qt::UserRole,
PLACE_ROLE = Qt::UserRole + 1
};
Ui::GameCheatSettingsWidget m_ui; Ui::GameCheatSettingsWidget m_ui;
QStandardItemModel* m_model = nullptr; QStandardItemModel* m_model = nullptr;
QSortFilterProxyModel* m_model_proxy = nullptr; QSortFilterProxyModel* m_model_proxy = nullptr;

View File

@ -90,6 +90,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="appliedLabel">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">

View File

@ -11888,12 +11888,12 @@ This action cannot be undone.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2675"/> <location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2697"/>
<source>Stencil buffers and texture barriers are both unavailable, this will break some graphical effects.</source> <source>Stencil buffers and texture barriers are both unavailable, this will break some graphical effects.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="5016"/> <location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="5038"/>
<source>Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. This might be really slow.</source> <source>Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. This might be really slow.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -11995,7 +11995,7 @@ Please see our official documentation for more information.</source>
<context> <context>
<name>GSDeviceVK</name> <name>GSDeviceVK</name>
<message> <message>
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2043"/> <location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="2062"/>
<source>Your GPU does not support the required Vulkan features.</source> <source>Your GPU does not support the required Vulkan features.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -12123,27 +12123,32 @@ Please see our official documentation for more information.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../Settings/GameCheatSettingsWidget.ui" line="109"/> <location filename="../Settings/GameCheatSettingsWidget.ui" line="116"/>
<source>Reload Cheats</source> <source>Reload Cheats</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../Settings/GameCheatSettingsWidget.cpp" line="61"/> <location filename="../Settings/GameCheatSettingsWidget.cpp" line="64"/>
<source>Show Cheats For All CRCs</source> <source>Show Cheats For All CRCs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../Settings/GameCheatSettingsWidget.cpp" line="61"/> <location filename="../Settings/GameCheatSettingsWidget.cpp" line="64"/>
<source>Checked</source> <source>Checked</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../Settings/GameCheatSettingsWidget.cpp" line="62"/> <location filename="../Settings/GameCheatSettingsWidget.cpp" line="65"/>
<source>Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded.</source> <source>Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../Settings/GameCheatSettingsWidget.cpp" line="236"/> <location filename="../Settings/GameCheatSettingsWidget.cpp" line="137"/>
<source>&lt;strong&gt;Applied:&lt;/strong&gt; %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../Settings/GameCheatSettingsWidget.cpp" line="290"/>
<source>%1 unlabelled patch codes will automatically activate.</source> <source>%1 unlabelled patch codes will automatically activate.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -18237,13 +18242,13 @@ Right click to clear binding</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1573"/> <location filename="../MainWindow.cpp" line="1600"/>
<location filename="../MainWindow.cpp" line="1634"/> <location filename="../MainWindow.cpp" line="1661"/>
<source>Change Disc</source> <source>Change Disc</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3023"/> <location filename="../MainWindow.cpp" line="3096"/>
<source>Load State</source> <source>Load State</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -18813,52 +18818,52 @@ Right click to clear binding</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1677"/> <location filename="../MainWindow.cpp" line="1704"/>
<source>Start Big Picture Mode</source> <source>Start Big Picture Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.ui" line="1018"/> <location filename="../MainWindow.ui" line="1018"/>
<location filename="../MainWindow.cpp" line="1678"/> <location filename="../MainWindow.cpp" line="1705"/>
<source>Big Picture</source> <source>Big Picture</source>
<comment>In Toolbar</comment> <comment>In Toolbar</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="667"/> <location filename="../MainWindow.cpp" line="674"/>
<source>Show Advanced Settings</source> <source>Show Advanced Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="739"/> <location filename="../MainWindow.cpp" line="746"/>
<location filename="../MainWindow.cpp" line="779"/> <location filename="../MainWindow.cpp" line="786"/>
<source>Video Capture</source> <source>Video Capture</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="248"/> <location filename="../MainWindow.cpp" line="255"/>
<source>Internal Resolution</source> <source>Internal Resolution</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="248"/> <location filename="../MainWindow.cpp" line="255"/>
<source>%1x Scale</source> <source>%1x Scale</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="645"/> <location filename="../MainWindow.cpp" line="652"/>
<source>Select location to save block dump:</source> <source>Select location to save block dump:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="663"/> <location filename="../MainWindow.cpp" line="670"/>
<location filename="../MainWindow.cpp" line="1247"/> <location filename="../MainWindow.cpp" line="1274"/>
<location filename="../MainWindow.cpp" line="1292"/> <location filename="../MainWindow.cpp" line="1319"/>
<source>Do not show again</source> <source>Do not show again</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="668"/> <location filename="../MainWindow.cpp" line="675"/>
<source>Changing advanced settings can have unpredictable effects on games, including graphical glitches, lock-ups, and even corrupted save files. We do not recommend changing advanced settings unless you know what you are doing, and the implications of changing each setting. <source>Changing advanced settings can have unpredictable effects on games, including graphical glitches, lock-ups, and even corrupted save files. We do not recommend changing advanced settings unless you know what you are doing, and the implications of changing each setting.
The PCSX2 team will not provide any support for configurations that modify these settings, you are on your own. The PCSX2 team will not provide any support for configurations that modify these settings, you are on your own.
@ -18867,371 +18872,371 @@ Are you sure you want to continue?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="723"/> <location filename="../MainWindow.cpp" line="730"/>
<source>Record On Boot</source> <source>Record On Boot</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="731"/> <location filename="../MainWindow.cpp" line="738"/>
<source>Did you want to start recording on boot?</source> <source>Did you want to start recording on boot?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="736"/> <location filename="../MainWindow.cpp" line="743"/>
<location filename="../MainWindow.cpp" line="776"/> <location filename="../MainWindow.cpp" line="783"/>
<source>%1 Files (*.%2)</source> <source>%1 Files (*.%2)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="745"/> <location filename="../MainWindow.cpp" line="752"/>
<source>Did you want to cancel recording on boot?</source> <source>Did you want to cancel recording on boot?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="769"/> <location filename="../MainWindow.cpp" line="776"/>
<source>Recording will start in a moment</source> <source>Recording will start in a moment</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1129"/> <location filename="../MainWindow.cpp" line="1156"/>
<source>WARNING: Memory Card Busy</source> <source>WARNING: Memory Card Busy</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1133"/> <location filename="../MainWindow.cpp" line="1160"/>
<source>Your memory card is still saving data.</source> <source>Your memory card is still saving data.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1134"/> <location filename="../MainWindow.cpp" line="1161"/>
<source>WARNING: Shutting down now can &lt;b&gt;IRREVERSIBLY CORRUPT YOUR MEMORY CARD.&lt;/b&gt;&lt;br&gt;&lt;br&gt;You are strongly advised to select &apos;No&apos; and let the save finish.&lt;br&gt;&lt;br&gt;Do you want to shutdown anyway and &lt;b&gt;IRREVERSIBLY CORRUPT YOUR MEMORY CARD&lt;/b&gt;?</source> <source>WARNING: Shutting down now can &lt;b&gt;IRREVERSIBLY CORRUPT YOUR MEMORY CARD.&lt;/b&gt;&lt;br&gt;&lt;br&gt;You are strongly advised to select &apos;No&apos; and let the save finish.&lt;br&gt;&lt;br&gt;Do you want to shutdown anyway and &lt;b&gt;IRREVERSIBLY CORRUPT YOUR MEMORY CARD&lt;/b&gt;?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1236"/> <location filename="../MainWindow.cpp" line="1263"/>
<source>Failed to Load State From Backup Slot %1</source> <source>Failed to Load State From Backup Slot %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1238"/> <location filename="../MainWindow.cpp" line="1265"/>
<source>Failed to Load State From Slot %1</source> <source>Failed to Load State From Slot %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1242"/> <location filename="../MainWindow.cpp" line="1269"/>
<source>Failed to Load State</source> <source>Failed to Load State</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1286"/> <location filename="../MainWindow.cpp" line="1313"/>
<source>Failed to Save State To Slot %1</source> <source>Failed to Save State To Slot %1</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1288"/> <location filename="../MainWindow.cpp" line="1315"/>
<source>Failed to Save State</source> <source>Failed to Save State</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1362"/> <location filename="../MainWindow.cpp" line="1389"/>
<source>Confirm Shutdown</source> <source>Confirm Shutdown</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1365"/> <location filename="../MainWindow.cpp" line="1392"/>
<source>Are you sure you want to shut down the virtual machine?</source> <source>Are you sure you want to shut down the virtual machine?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1367"/> <location filename="../MainWindow.cpp" line="1394"/>
<source>Save State For Resume</source> <source>Save State For Resume</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1473"/> <location filename="../MainWindow.cpp" line="1500"/>
<location filename="../MainWindow.cpp" line="1864"/> <location filename="../MainWindow.cpp" line="1891"/>
<location filename="../MainWindow.cpp" line="2328"/> <location filename="../MainWindow.cpp" line="2355"/>
<location filename="../MainWindow.cpp" line="2492"/> <location filename="../MainWindow.cpp" line="2523"/>
<location filename="../MainWindow.cpp" line="2903"/> <location filename="../MainWindow.cpp" line="2976"/>
<location filename="../MainWindow.cpp" line="2999"/> <location filename="../MainWindow.cpp" line="3072"/>
<location filename="../MainWindow.cpp" line="3042"/> <location filename="../MainWindow.cpp" line="3115"/>
<source>Error</source> <source>Error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1473"/> <location filename="../MainWindow.cpp" line="1500"/>
<source>You must select a disc to change discs.</source> <source>You must select a disc to change discs.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1504"/> <location filename="../MainWindow.cpp" line="1531"/>
<source>Properties...</source> <source>Properties...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1520"/> <location filename="../MainWindow.cpp" line="1547"/>
<source>Set Cover Image...</source> <source>Set Cover Image...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1524"/> <location filename="../MainWindow.cpp" line="1551"/>
<source>Create Game Shortcut...</source> <source>Create Game Shortcut...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1527"/> <location filename="../MainWindow.cpp" line="1554"/>
<source>Exclude From List</source> <source>Exclude From List</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1533"/> <location filename="../MainWindow.cpp" line="1560"/>
<source>Reset Play Time</source> <source>Reset Play Time</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1537"/> <location filename="../MainWindow.cpp" line="1564"/>
<source>Check Wiki Page</source> <source>Check Wiki Page</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1545"/> <location filename="../MainWindow.cpp" line="1572"/>
<source>Default Boot</source> <source>Default Boot</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1552"/> <location filename="../MainWindow.cpp" line="1579"/>
<source>Fast Boot</source> <source>Fast Boot</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1555"/> <location filename="../MainWindow.cpp" line="1582"/>
<source>Full Boot</source> <source>Full Boot</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1560"/> <location filename="../MainWindow.cpp" line="1587"/>
<source>Boot and Debug</source> <source>Boot and Debug</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1584"/> <location filename="../MainWindow.cpp" line="1611"/>
<source>Add Search Directory...</source> <source>Add Search Directory...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1593"/> <location filename="../MainWindow.cpp" line="1620"/>
<source>Start File</source> <source>Start File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1602"/> <location filename="../MainWindow.cpp" line="1629"/>
<source>Start Disc</source> <source>Start Disc</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1619"/> <location filename="../MainWindow.cpp" line="1646"/>
<source>Select Disc Image</source> <source>Select Disc Image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1763"/> <location filename="../MainWindow.cpp" line="1790"/>
<source>Updater Error</source> <source>Updater Error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1769"/> <location filename="../MainWindow.cpp" line="1796"/>
<source>&lt;p&gt;Sorry, you are trying to update a PCSX2 version which is not an official GitHub release. To prevent incompatibilities, the auto-updater is only enabled on official builds.&lt;/p&gt;&lt;p&gt;To obtain an official build, please download from the link below:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://pcsx2.net/downloads/&quot;&gt;https://pcsx2.net/downloads/&lt;/a&gt;&lt;/p&gt;</source> <source>&lt;p&gt;Sorry, you are trying to update a PCSX2 version which is not an official GitHub release. To prevent incompatibilities, the auto-updater is only enabled on official builds.&lt;/p&gt;&lt;p&gt;To obtain an official build, please download from the link below:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://pcsx2.net/downloads/&quot;&gt;https://pcsx2.net/downloads/&lt;/a&gt;&lt;/p&gt;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1774"/> <location filename="../MainWindow.cpp" line="1801"/>
<source>Automatic updating is not supported on the current platform.</source> <source>Automatic updating is not supported on the current platform.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1854"/> <location filename="../MainWindow.cpp" line="1881"/>
<source>Confirm File Creation</source> <source>Confirm File Creation</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1855"/> <location filename="../MainWindow.cpp" line="1882"/>
<source>The pnach file &apos;%1&apos; does not currently exist. Do you want to create it?</source> <source>The pnach file &apos;%1&apos; does not currently exist. Do you want to create it?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1864"/> <location filename="../MainWindow.cpp" line="1891"/>
<source>Failed to create &apos;%1&apos;.</source> <source>Failed to create &apos;%1&apos;.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1960"/> <location filename="../MainWindow.cpp" line="1987"/>
<source>Input Recording Failed</source> <source>Input Recording Failed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1961"/> <location filename="../MainWindow.cpp" line="1988"/>
<source>Failed to create file: {}</source> <source>Failed to create file: {}</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1983"/> <location filename="../MainWindow.cpp" line="2010"/>
<source>Select a File</source> <source>Select a File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1984"/> <location filename="../MainWindow.cpp" line="2011"/>
<source>Input Recording Files (*.p2m2)</source> <source>Input Recording Files (*.p2m2)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2019"/> <location filename="../MainWindow.cpp" line="2046"/>
<source>Input Playback Failed</source> <source>Input Playback Failed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2020"/> <location filename="../MainWindow.cpp" line="2047"/>
<source>Failed to open file: {}</source> <source>Failed to open file: {}</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2106"/> <location filename="../MainWindow.cpp" line="2133"/>
<source>Paused</source> <source>Paused</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2292"/> <location filename="../MainWindow.cpp" line="2319"/>
<source>Load State Failed</source> <source>Load State Failed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2292"/> <location filename="../MainWindow.cpp" line="2319"/>
<source>Cannot load a save state without a running VM.</source> <source>Cannot load a save state without a running VM.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2316"/> <location filename="../MainWindow.cpp" line="2343"/>
<source>The new ELF cannot be loaded without resetting the virtual machine. Do you want to reset the virtual machine now?</source> <source>The new ELF cannot be loaded without resetting the virtual machine. Do you want to reset the virtual machine now?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2328"/> <location filename="../MainWindow.cpp" line="2355"/>
<source>Cannot change from game to GS dump without shutting down first.</source> <source>Cannot change from game to GS dump without shutting down first.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2492"/> <location filename="../MainWindow.cpp" line="2523"/>
<source>Failed to get window info from widget</source> <source>Failed to get window info from widget</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1677"/> <location filename="../MainWindow.cpp" line="1704"/>
<source>Stop Big Picture Mode</source> <source>Stop Big Picture Mode</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1678"/> <location filename="../MainWindow.cpp" line="1705"/>
<source>Exit Big Picture</source> <source>Exit Big Picture</source>
<comment>In Toolbar</comment> <comment>In Toolbar</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2809"/> <location filename="../MainWindow.cpp" line="2882"/>
<source>Game Properties</source> <source>Game Properties</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2809"/> <location filename="../MainWindow.cpp" line="2882"/>
<source>Game properties is unavailable for the current game.</source> <source>Game properties is unavailable for the current game.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2861"/> <location filename="../MainWindow.cpp" line="2934"/>
<source>Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient permissions to access it.</source> <source>Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient permissions to access it.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2879"/> <location filename="../MainWindow.cpp" line="2952"/>
<source>Select disc drive:</source> <source>Select disc drive:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2903"/> <location filename="../MainWindow.cpp" line="2976"/>
<source>This save state does not exist.</source> <source>This save state does not exist.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2916"/> <location filename="../MainWindow.cpp" line="2989"/>
<source>Select Cover Image</source> <source>Select Cover Image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2933"/> <location filename="../MainWindow.cpp" line="3006"/>
<source>Cover Already Exists</source> <source>Cover Already Exists</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2934"/> <location filename="../MainWindow.cpp" line="3007"/>
<source>A cover image for this game already exists, do you wish to replace it?</source> <source>A cover image for this game already exists, do you wish to replace it?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2929"/> <location filename="../MainWindow.cpp" line="3002"/>
<location filename="../MainWindow.cpp" line="2943"/> <location filename="../MainWindow.cpp" line="3016"/>
<location filename="../MainWindow.cpp" line="2949"/> <location filename="../MainWindow.cpp" line="3022"/>
<location filename="../MainWindow.cpp" line="2955"/> <location filename="../MainWindow.cpp" line="3028"/>
<source>Copy Error</source> <source>Copy Error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2943"/> <location filename="../MainWindow.cpp" line="3016"/>
<source>Failed to remove existing cover &apos;%1&apos;</source> <source>Failed to remove existing cover &apos;%1&apos;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2949"/> <location filename="../MainWindow.cpp" line="3022"/>
<source>Failed to copy &apos;%1&apos; to &apos;%2&apos;</source> <source>Failed to copy &apos;%1&apos; to &apos;%2&apos;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2955"/> <location filename="../MainWindow.cpp" line="3028"/>
<source>Failed to remove &apos;%1&apos;</source> <source>Failed to remove &apos;%1&apos;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2315"/> <location filename="../MainWindow.cpp" line="2342"/>
<location filename="../MainWindow.cpp" line="2964"/> <location filename="../MainWindow.cpp" line="3037"/>
<source>Confirm Reset</source> <source>Confirm Reset</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="1539"/> <location filename="../MainWindow.cpp" line="1566"/>
<source>Open Snapshots Folder</source> <source>Open Snapshots Folder</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2916"/> <location filename="../MainWindow.cpp" line="2989"/>
<source>All Cover Image Types (*.jpg *.jpeg *.png *.webp)</source> <source>All Cover Image Types (*.jpg *.jpeg *.png *.webp)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2929"/> <location filename="../MainWindow.cpp" line="3002"/>
<source>You must select a different file to the current cover image.</source> <source>You must select a different file to the current cover image.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2999"/> <location filename="../MainWindow.cpp" line="3072"/>
<source>Failed to create snapshots directory &apos;%1&apos; <source>Failed to create snapshots directory &apos;%1&apos;
Opening default directory.</source> Opening default directory.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3017"/> <location filename="../MainWindow.cpp" line="3090"/>
<source>Load Resume State</source> <source>Load Resume State</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3020"/> <location filename="../MainWindow.cpp" line="3093"/>
<source>A resume save state was found for this game, saved at: <source>A resume save state was found for this game, saved at:
%1. %1.
@ -19240,43 +19245,43 @@ Do you want to load this state, or start from a fresh boot?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3024"/> <location filename="../MainWindow.cpp" line="3097"/>
<source>Fresh Boot</source> <source>Fresh Boot</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3025"/> <location filename="../MainWindow.cpp" line="3098"/>
<source>Delete And Boot</source> <source>Delete And Boot</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3042"/> <location filename="../MainWindow.cpp" line="3115"/>
<source>Failed to delete save state file &apos;%1&apos;.</source> <source>Failed to delete save state file &apos;%1&apos;.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3100"/> <location filename="../MainWindow.cpp" line="3173"/>
<source>Load State File...</source> <source>Load State File...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3100"/> <location filename="../MainWindow.cpp" line="3173"/>
<source>Load From File...</source> <source>Load From File...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3103"/> <location filename="../MainWindow.cpp" line="3176"/>
<location filename="../MainWindow.cpp" line="3177"/> <location filename="../MainWindow.cpp" line="3250"/>
<source>Select Save State File</source> <source>Select Save State File</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3148"/> <location filename="../MainWindow.cpp" line="3221"/>
<source>Load Backup Slot %1 (%2)</source> <source>Load Backup Slot %1 (%2)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../MainWindow.cpp" line="3165"/> <location filename="../MainWindow.cpp" line="3238"/>
<source>%n save states deleted.</source> <source>%n save states deleted.</source>
<translation type="unfinished"> <translation type="unfinished">
<numerusform></numerusform> <numerusform></numerusform>
@ -19284,12 +19289,12 @@ Do you want to load this state, or start from a fresh boot?</source>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3177"/> <location filename="../MainWindow.cpp" line="3250"/>
<source>Save States (*.p2s)</source> <source>Save States (*.p2s)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3110"/> <location filename="../MainWindow.cpp" line="3183"/>
<source>Delete Save States...</source> <source>Delete Save States...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -19304,7 +19309,7 @@ Do you want to load this state, or start from a fresh boot?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2965"/> <location filename="../MainWindow.cpp" line="3038"/>
<source>Are you sure you want to reset the play time for &apos;%1&apos; (%2)? <source>Are you sure you want to reset the play time for &apos;%1&apos; (%2)?
Your current play time is %3. Your current play time is %3.
@ -19313,75 +19318,75 @@ This action cannot be undone.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2966"/> <location filename="../MainWindow.cpp" line="3039"/>
<source>empty title</source> <source>empty title</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="2967"/> <location filename="../MainWindow.cpp" line="3040"/>
<source>no serial</source> <source>no serial</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3103"/> <location filename="../MainWindow.cpp" line="3176"/>
<source>Save States (*.p2s *.p2s.backup)</source> <source>Save States (*.p2s *.p2s.backup)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3120"/> <location filename="../MainWindow.cpp" line="3193"/>
<source>Resume (%2)</source> <source>Resume (%2)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3136"/> <location filename="../MainWindow.cpp" line="3209"/>
<source>Load Slot %1 (%2)</source> <source>Load Slot %1 (%2)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3157"/> <location filename="../MainWindow.cpp" line="3230"/>
<location filename="../MainWindow.cpp" line="3165"/> <location filename="../MainWindow.cpp" line="3238"/>
<source>Delete Save States</source> <source>Delete Save States</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3158"/> <location filename="../MainWindow.cpp" line="3231"/>
<source>Are you sure you want to delete all save states for %1? <source>Are you sure you want to delete all save states for %1?
The saves will not be recoverable.</source> The saves will not be recoverable.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3175"/> <location filename="../MainWindow.cpp" line="3248"/>
<source>Save To File...</source> <source>Save To File...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3195"/> <location filename="../MainWindow.cpp" line="3268"/>
<source>Empty</source> <source>Empty</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3197"/> <location filename="../MainWindow.cpp" line="3270"/>
<source>Save Slot %1 (%2)</source> <source>Save Slot %1 (%2)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3256"/> <location filename="../MainWindow.cpp" line="3329"/>
<source>Confirm Disc Change</source> <source>Confirm Disc Change</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3257"/> <location filename="../MainWindow.cpp" line="3330"/>
<source>Do you want to swap discs or boot the new image (via system reset)?</source> <source>Do you want to swap discs or boot the new image (via system reset)?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3258"/> <location filename="../MainWindow.cpp" line="3331"/>
<source>Swap Disc</source> <source>Swap Disc</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../MainWindow.cpp" line="3259"/> <location filename="../MainWindow.cpp" line="3332"/>
<source>Reset</source> <source>Reset</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -21247,7 +21252,7 @@ Ejecting {2} and replacing it with {3}.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../pcsx2/Patch.cpp" line="819"/> <location filename="../../pcsx2/Patch.cpp" line="820"/>
<source>%n GameDB patches are active.</source> <source>%n GameDB patches are active.</source>
<comment>OSD Message</comment> <comment>OSD Message</comment>
<translation type="unfinished"> <translation type="unfinished">
@ -21256,7 +21261,7 @@ Ejecting {2} and replacing it with {3}.</source>
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../pcsx2/Patch.cpp" line="827"/> <location filename="../../pcsx2/Patch.cpp" line="828"/>
<source>%n game patches are active.</source> <source>%n game patches are active.</source>
<comment>OSD Message</comment> <comment>OSD Message</comment>
<translation type="unfinished"> <translation type="unfinished">
@ -21265,7 +21270,7 @@ Ejecting {2} and replacing it with {3}.</source>
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../../pcsx2/Patch.cpp" line="836"/> <location filename="../../pcsx2/Patch.cpp" line="837"/>
<source>%n cheat patches are active.</source> <source>%n cheat patches are active.</source>
<comment>OSD Message</comment> <comment>OSD Message</comment>
<translation type="unfinished"> <translation type="unfinished">
@ -21274,36 +21279,36 @@ Ejecting {2} and replacing it with {3}.</source>
</translation> </translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/Patch.cpp" line="850"/> <location filename="../../pcsx2/Patch.cpp" line="851"/>
<source>No cheats or patches (widescreen, compatibility or others) are found / enabled.</source> <source>No cheats or patches (widescreen, compatibility or others) are found / enabled.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/Patch.cpp" line="1807"/> <location filename="../../pcsx2/Patch.cpp" line="1808"/>
<source>Unknown</source> <source>Unknown</source>
<extracomment>Time when a patch is applied.</extracomment> <extracomment>Time when a patch is applied.</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/Patch.cpp" line="1813"/> <location filename="../../pcsx2/Patch.cpp" line="1814"/>
<source>Only On Startup</source> <source>Only On Startup</source>
<extracomment>Time when a patch is applied.</extracomment> <extracomment>Time when a patch is applied.</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/Patch.cpp" line="1816"/> <location filename="../../pcsx2/Patch.cpp" line="1817"/>
<source>Every Frame</source> <source>Every Frame</source>
<extracomment>Time when a patch is applied.</extracomment> <extracomment>Time when a patch is applied.</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/Patch.cpp" line="1819"/> <location filename="../../pcsx2/Patch.cpp" line="1820"/>
<source>On Startup &amp; Every Frame</source> <source>On Startup &amp; Every Frame</source>
<extracomment>Time when a patch is applied.</extracomment> <extracomment>Time when a patch is applied.</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/Patch.cpp" line="1822"/> <location filename="../../pcsx2/Patch.cpp" line="1823"/>
<source>On Startup &amp; When Enabled</source> <source>On Startup &amp; When Enabled</source>
<extracomment>Time when a patch is applied.</extracomment> <extracomment>Time when a patch is applied.</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -21588,12 +21593,12 @@ If you have any unsaved progress on this save state, you can download the compat
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/SaveState.cpp" line="1255"/> <location filename="../../pcsx2/SaveState.cpp" line="1258"/>
<source>Failed to load state from slot {}: {}</source> <source>Failed to load state from slot {}: {}</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../pcsx2/SaveState.cpp" line="1258"/> <location filename="../../pcsx2/SaveState.cpp" line="1255"/>
<source>Failed to load state from backup slot {}: {}</source> <source>Failed to load state from backup slot {}: {}</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View File

@ -165,11 +165,12 @@ bool GSDevice12::CreateDevice(u32& vendor_id)
// Enabling the debug layer will fail if the Graphics Tools feature is not installed. // Enabling the debug layer will fail if the Graphics Tools feature is not installed.
if (enable_debug_layer) if (enable_debug_layer)
{ {
ComPtr<ID3D12Debug> debug12; ComPtr<ID3D12Debug1> debug12;
hr = D3D12GetDebugInterface(IID_PPV_ARGS(debug12.put())); hr = D3D12GetDebugInterface(IID_PPV_ARGS(debug12.put()));
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
debug12->EnableDebugLayer(); debug12->EnableDebugLayer();
debug12->SetEnableGPUBasedValidation(true);
} }
else else
{ {
@ -1224,8 +1225,8 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id)
{ {
//const bool isAMD = (vendor_id == 0x1002 || vendor_id == 0x1022); //const bool isAMD = (vendor_id == 0x1002 || vendor_id == 0x1022);
m_features.texture_barrier = false; m_features.texture_barrier = GSConfig.OverrideTextureBarriers != 0;
m_features.multidraw_fb_copy = GSConfig.OverrideTextureBarriers != 0; m_features.multidraw_fb_copy = false;
m_features.broken_point_sampler = false; m_features.broken_point_sampler = false;
m_features.primitive_id = true; m_features.primitive_id = true;
m_features.prefer_new_textures = true; m_features.prefer_new_textures = true;
@ -3207,7 +3208,7 @@ void GSDevice12::SetStencilRef(u8 ref)
m_dirty_flags |= DIRTY_FLAG_STENCIL_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; D3D12DescriptorHandle handle;
if (sr) 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->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
} }
dtex->SetUseFenceCounter(GetCurrentFenceValue()); dtex->SetUseFenceCounter(GetCurrentFenceValue());
handle = dtex->GetSRVDescriptor(); handle = feedback ? dtex->GetFBLDescriptor() : dtex->GetSRVDescriptor();
} }
else else
{ {
@ -3312,7 +3313,7 @@ void GSDevice12::UnbindTexture(GSTexture12* tex)
{ {
for (u32 i = 0; i < NUM_TOTAL_TFX_TEXTURES; i++) 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_tfx_textures[i] = m_null_texture->GetSRVDescriptor();
m_dirty_flags |= DIRTY_FLAG_TFX_TEXTURES; m_dirty_flags |= DIRTY_FLAG_TFX_TEXTURES;
@ -3826,12 +3827,24 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// TODO: Backport from vk. // TODO: Backport from vk.
if (stencil_DATE_One) if (stencil_DATE_One)
{
config.ps.date = 0; 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* colclip_rt = static_cast<GSTexture12*>(g_gs_device->GetColorClipTexture());
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt); GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds); GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
GSTexture12* draw_rt_clone = nullptr;
// Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank). // Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank).
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize()); const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
@ -3955,7 +3968,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
} }
// we're not drawing to the RT, so we can use it as a source // 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); PSSetShaderResource(2, draw_rt, true);
} }
@ -3985,14 +3998,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
m_pipeline_selector.ds = true; 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));
{
// 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)
Console.Warning("D3D12: Failed to allocate temp texture for RT copy.");
}
OMSetRenderTargets(draw_rt, draw_ds, config.scissor); OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
@ -4011,8 +4017,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, 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 : stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE :
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
stencil_DATE ? (draw_rt_clone ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : stencil_DATE ? (feedback ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE :
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) :
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1); clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
} }
@ -4040,7 +4046,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
UploadHWDrawVerticesAndIndices(config); UploadHWDrawVerticesAndIndices(config);
// now we can do the actual draw // 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 // blend second pass
if (config.blend_multi_pass.enable) if (config.blend_multi_pass.enable)
@ -4070,12 +4076,9 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
pipe.cms = config.alpha_second_pass.colormask; pipe.cms = config.alpha_second_pass.colormask;
pipe.dss = config.alpha_second_pass.depth; pipe.dss = config.alpha_second_pass.depth;
pipe.bs = config.blend; 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) if (date_image)
Recycle(date_image); Recycle(date_image);
@ -4113,43 +4116,39 @@ 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 (feedback)
{ {
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD
if ((one_barrier || full_barrier) && !config.ps.IsFeedbackLoop()) [[unlikely]] if ((one_barrier || full_barrier) && !config.ps.IsFeedbackLoop()) [[unlikely]]
Console.Warning("D3D12: Possible unnecessary copy detected."); Console.Warning("D3D12: Possible unnecessary barrier detected.");
#endif #endif
auto CopyAndBind = [&](GSVector4i drawarea) { if (one_barrier || full_barrier)
EndRenderPass(); 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); if (full_barrier)
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)
{ {
pxAssert(config.drawlist && !config.drawlist->empty());
const u32 draw_list_size = static_cast<u32>(config.drawlist->size()); const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
const u32 indices_per_prim = config.indices_per_prim; const u32 indices_per_prim = config.indices_per_prim;
pxAssert(config.drawlist && !config.drawlist->empty()); GL_PUSH("Split the draw");
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size); g_perfmon.Put(GSPerfMon::Barriers, draw_list_size);
for (u32 n = 0, p = 0; n < draw_list_size; n++) for (u32 n = 0, p = 0; n < draw_list_size; n++)
{ {
const u32 count = (*config.drawlist)[n] * indices_per_prim; 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)) if (BindDrawPipeline(pipe))
DrawIndexedPrimitive(p, count); DrawIndexedPrimitive(p, count);
p += count; p += count;
@ -4158,10 +4157,16 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig&
return; 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. EndRenderPass();
if (!skip_first_barrier) // Specify null for the after resource as both resources are used after the barrier.
CopyAndBind(config.drawarea); 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)) if (BindDrawPipeline(pipe))

View File

@ -456,7 +456,7 @@ public:
void IASetVertexBuffer(const void* vertex, size_t stride, size_t count); void IASetVertexBuffer(const void* vertex, size_t stride, size_t count);
void IASetIndexBuffer(const void* index, 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 PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor); void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor);
@ -466,7 +466,7 @@ public:
bool BindDrawPipeline(const PipelineSelector& p); bool BindDrawPipeline(const PipelineSelector& p);
void RenderHW(GSHWDrawConfig& config) override; 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 UpdateHWPipelineSelector(GSHWDrawConfig& config);
void UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config); void UploadHWDrawVerticesAndIndices(const GSHWDrawConfig& config);

View File

@ -15,14 +15,17 @@
#include "D3D12MemAlloc.h" #include "D3D12MemAlloc.h"
GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format, 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, wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor, wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state) 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(std::move(resource))
, m_resource_fbl(std::move(resource_fbl))
, m_allocation(std::move(allocation)) , m_allocation(std::move(allocation))
, m_srv_descriptor(srv_descriptor) , m_srv_descriptor(srv_descriptor)
, m_write_descriptor(write_descriptor) , m_write_descriptor(write_descriptor)
, m_uav_descriptor(uav_descriptor) , m_uav_descriptor(uav_descriptor)
, m_fbl_descriptor(fbl_descriptor)
, m_write_descriptor_type(wdtype) , m_write_descriptor_type(wdtype)
, m_dxgi_format(dxgi_format) , m_dxgi_format(dxgi_format)
, m_resource_state(resource_state) , m_resource_state(resource_state)
@ -64,8 +67,13 @@ void GSTexture12::Destroy(bool defer)
if (m_uav_descriptor) if (m_uav_descriptor)
dev->DeferDescriptorDestruction(dev->GetDescriptorHeapManager(), &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.get());
dev->DeferResourceDestruction(m_allocation.get(), m_resource_fbl.get());
m_resource.reset(); m_resource.reset();
m_resource_fbl.reset();
m_allocation.reset(); m_allocation.reset();
} }
else else
@ -88,7 +96,11 @@ void GSTexture12::Destroy(bool defer)
if (m_uav_descriptor) if (m_uav_descriptor)
dev->GetDescriptorHeapManager().Free(&m_uav_descriptor); dev->GetDescriptorHeapManager().Free(&m_uav_descriptor);
if (m_fbl_descriptor)
dev->GetDescriptorHeapManager().Free(&m_fbl_descriptor);
m_resource.reset(); m_resource.reset();
m_resource_fbl.reset();
m_allocation.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. // RT's tend to be larger, so we'll keep them committed for speed.
pxAssert(levels == 1); pxAssert(levels == 1);
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED; 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; optimized_clear_value.Format = rtv_format;
state = D3D12_RESOURCE_STATE_RENDER_TARGET; 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; desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
wil::com_ptr_nothrow<ID3D12Resource> resource; wil::com_ptr_nothrow<ID3D12Resource> resource;
wil::com_ptr_nothrow<ID3D12Resource> resource_fbl;
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation; 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; WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
if (srv_format != DXGI_FORMAT_UNKNOWN) if (srv_format != DXGI_FORMAT_UNKNOWN)
{ {
@ -223,9 +280,20 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
return {}; 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>( return std::unique_ptr<GSTexture12>(
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(allocation), 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, write_descriptor_type, state)); 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, 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, 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, desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, uav_descriptor,
write_descriptor_type, resource_state)); {}, write_descriptor_type, resource_state));
} }
bool GSTexture12::CreateSRVDescriptor( bool GSTexture12::CreateSRVDescriptor(

View File

@ -31,9 +31,11 @@ public:
__fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; } __fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
__fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; } __fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; }
__fi const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_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 D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; }
__fi DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; } __fi DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; }
__fi ID3D12Resource* GetResource() const { return m_resource.get(); } __fi ID3D12Resource* GetResource() const { return m_resource.get(); }
__fi ID3D12Resource* GetFBLResource() const { return m_resource_fbl.get(); }
void* GetNativeHandle() const override; void* GetNativeHandle() const override;
@ -68,9 +70,10 @@ private:
}; };
GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format, 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, wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor, wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state); const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
static bool CreateSRVDescriptor( static bool CreateSRVDescriptor(
ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh); 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; 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;
wil::com_ptr_nothrow<ID3D12Resource> m_resource_fbl;
wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation; wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation;
D3D12DescriptorHandle m_srv_descriptor = {}; D3D12DescriptorHandle m_srv_descriptor = {};
D3D12DescriptorHandle m_write_descriptor = {}; D3D12DescriptorHandle m_write_descriptor = {};
D3D12DescriptorHandle m_uav_descriptor = {}; D3D12DescriptorHandle m_uav_descriptor = {};
D3D12DescriptorHandle m_fbl_descriptor = {};
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None; WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;
DXGI_FORMAT m_dxgi_format = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT m_dxgi_format = DXGI_FORMAT_UNKNOWN;

View File

@ -206,8 +206,7 @@ bool GSDeviceVK::SelectInstanceExtensions(ExtensionList* extension_list, const W
if (enable_debug_utils && !SupportsExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false)) if (enable_debug_utils && !SupportsExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false))
Console.Warning("VK: Debug report requested, but extension is not available."); Console.Warning("VK: Debug report requested, but extension is not available.");
oe->vk_ext_swapchain_maintenance1 = (wi.type != WindowInfo::Type::Surfaceless && oe->vk_swapchain_maintenance1 = wi.type != WindowInfo::Type::Surfaceless;
SupportsExtension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false));
// Needed for exclusive fullscreen control. // Needed for exclusive fullscreen control.
SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false); SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false);
@ -411,6 +410,13 @@ 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_ext_line_rasterization = SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false); m_optional_extensions.vk_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);
m_optional_extensions.vk_swapchain_maintenance1 = khr_swapchain_maintenance1 ? khr_swapchain_maintenance1 : 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 // 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 // is enabled, triggering errors by spirv-val. Gate it by an environment variable if you want source debugging until
// this is fixed. // this is fixed.
@ -420,10 +426,6 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab
SupportsExtension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, false); 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 #ifdef _WIN32
m_optional_extensions.vk_ext_full_screen_exclusive = m_optional_extensions.vk_ext_full_screen_exclusive =
enable_surface && SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false); enable_surface && SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false);
@ -611,8 +613,10 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = { VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; 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}; 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) if (m_optional_extensions.vk_ext_provoking_vertex)
{ {
@ -634,10 +638,18 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
attachment_feedback_loop_feature.attachmentFeedbackLoopLayout = VK_TRUE; attachment_feedback_loop_feature.attachmentFeedbackLoopLayout = VK_TRUE;
Vulkan::AddPointerToChain(&device_info, &attachment_feedback_loop_feature); 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; if (m_optional_extensions.vk_swapchain_maintenance1_is_khr)
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_feature); {
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); VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
@ -704,8 +716,10 @@ bool GSDeviceVK::ProcessDeviceExtensions()
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = { VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; 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}; 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 = { VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
@ -718,8 +732,10 @@ bool GSDeviceVK::ProcessDeviceExtensions()
Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature); Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature);
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout) if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature); Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature);
if (m_optional_extensions.vk_ext_swapchain_maintenance1) if (m_optional_extensions.vk_swapchain_maintenance1 && m_optional_extensions.vk_swapchain_maintenance1_is_khr)
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_feature); 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 // query
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2); vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
@ -794,8 +810,9 @@ bool GSDeviceVK::ProcessDeviceExtensions()
m_optional_extensions.vk_ext_calibrated_timestamps = false; m_optional_extensions.vk_ext_calibrated_timestamps = false;
} }
m_optional_extensions.vk_ext_swapchain_maintenance1 &= m_optional_extensions.vk_swapchain_maintenance1 &= m_optional_extensions.vk_swapchain_maintenance1_is_khr ?
(swapchain_maintenance1_feature.swapchainMaintenance1 == VK_TRUE); (swapchain_maintenance1_khr_feature.swapchainMaintenance1 == VK_TRUE) :
(swapchain_maintenance1_ext_feature.swapchainMaintenance1 == VK_TRUE);
Console.WriteLn( Console.WriteLn(
"VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported"); "VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
@ -805,8 +822,9 @@ bool GSDeviceVK::ProcessDeviceExtensions()
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported"); m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s", Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s",
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported"); m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_swapchain_maintenance1 is %s", Console.WriteLn("VK_%s_swapchain_maintenance1 is %s",
m_optional_extensions.vk_ext_swapchain_maintenance1 ? "supported" : "NOT supported"); 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", Console.WriteLn("VK_EXT_full_screen_exclusive is %s",
m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported"); m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported");
Console.WriteLn("VK_KHR_driver_properties is %s", Console.WriteLn("VK_KHR_driver_properties is %s",
@ -1266,7 +1284,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. // 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) 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 else
LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: "); LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: ");
@ -2183,6 +2202,8 @@ bool GSDeviceVK::UpdateWindow()
void GSDeviceVK::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) 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) && if (!m_swap_chain || (m_swap_chain->GetWidth() == static_cast<u32>(new_window_width) &&
m_swap_chain->GetHeight() == static_cast<u32>(new_window_height))) m_swap_chain->GetHeight() == static_cast<u32>(new_window_height)))
{ {
@ -2290,10 +2311,9 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
return PresentResult::FrameSkipped; 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) if (res != VK_SUCCESS)
{ {
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
m_swap_chain->ReleaseCurrentImage(); m_swap_chain->ReleaseCurrentImage();
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
@ -2313,6 +2333,8 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
res = m_swap_chain->AcquireNextImage(); res = m_swap_chain->AcquireNextImage();
} }
else
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
// This can happen when multiple resize events happen in quick succession. // This can happen when multiple resize events happen in quick succession.
// In this case, just wait until the next frame to try again. // In this case, just wait until the next frame to try again.

View File

@ -41,7 +41,8 @@ public:
bool vk_ext_rasterization_order_attachment_access : 1; bool vk_ext_rasterization_order_attachment_access : 1;
bool vk_ext_full_screen_exclusive : 1; bool vk_ext_full_screen_exclusive : 1;
bool vk_ext_line_rasterization : 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_driver_properties : 1;
bool vk_khr_shader_non_semantic_info : 1; bool vk_khr_shader_non_semantic_info : 1;
bool vk_ext_attachment_feedback_loop_layout : 1; bool vk_ext_attachment_feedback_loop_layout : 1;
@ -367,6 +368,7 @@ public:
private: private:
std::unique_ptr<VKSwapChain> m_swap_chain; std::unique_ptr<VKSwapChain> m_swap_chain;
bool m_resize_requested = false;
VkDescriptorSetLayout m_utility_ds_layout = VK_NULL_HANDLE; VkDescriptorSetLayout m_utility_ds_layout = VK_NULL_HANDLE;
VkPipelineLayout m_utility_pipeline_layout = VK_NULL_HANDLE; VkPipelineLayout m_utility_pipeline_layout = VK_NULL_HANDLE;

View File

@ -241,4 +241,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkCmdPushDescriptorSetKHR, false)
// VK_EXT_swapchain_maintenance1 // VK_EXT_swapchain_maintenance1
VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesEXT, false) VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesEXT, false)
// VK_KHR_swapchain_maintenance1
VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesKHR, false)
#endif // VULKAN_DEVICE_ENTRY_POINT #endif // VULKAN_DEVICE_ENTRY_POINT

View File

@ -366,7 +366,17 @@ bool VKSwapChain::CreateSwapChain()
// Store the old/current swap chain when recreating for resize // Store the old/current swap chain when recreating for resize
// Old swap chain is destroyed regardless of whether the create call succeeds // 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; m_swap_chain = VK_NULL_HANDLE;
// Now we can actually create the swap chain // Now we can actually create the swap chain
@ -549,17 +559,29 @@ void VKSwapChain::ReleaseCurrentImage()
return; return;
if ((m_image_acquire_result.value() == VK_SUCCESS || m_image_acquire_result.value() == VK_SUBOPTIMAL_KHR) && 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(); GSDeviceVK::GetInstance()->WaitForGPUIdle();
const VkReleaseSwapchainImagesInfoEXT info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT, VkResult res;
.swapchain = m_swap_chain, if (GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1_is_khr)
.imageIndexCount = 1, {
.pImageIndices = &m_current_image}; const VkReleaseSwapchainImagesInfoKHR info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR,
VkResult res = vkReleaseSwapchainImagesEXT(GSDeviceVK::GetInstance()->GetDevice(), &info); .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) if (res != VK_SUCCESS)
LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImagesEXT() failed: "); LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImages() failed: ");
} }
m_image_acquire_result.reset(); m_image_acquire_result.reset();

View File

@ -553,7 +553,7 @@ void Patch::ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pna
(*num_unlabelled_patches)++; (*num_unlabelled_patches)++;
// Try to extract the place value of the patch lines so we can // 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. // all this parsing logic twice.
if (unknown_place) if (unknown_place)
continue; continue;
@ -571,6 +571,7 @@ void Patch::ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pna
// place values. // place values.
current_patch.place = std::nullopt; current_patch.place = std::nullopt;
unknown_place = true; unknown_place = true;
continue;
} }
current_patch.place = place; current_patch.place = place;