Compare commits

...

58 Commits

Author SHA1 Message Date
lightningterror 1f0f3b92b3 GS/DX12: Expand the fb optimization hit detection. 2026-07-02 11:21:49 +02:00
JordanTheToaster fe3ce7f578 GameDB: Various Gran Turismo fixes 2026-07-01 11:40:37 +02:00
PCSX2 Bot 51c995168a [ci skip] PAD: Update to latest controller database. 2026-06-29 18:57:33 +02:00
PCSX2 Bot f83e4ff4bf [ci skip] Qt: Update Base Translation. 2026-06-28 20:26:52 -04:00
chaoticgd b67e793283 PINE: Disallow access to pages with custom VTLB handlers 2026-06-28 16:46:13 -04:00
chaoticgd d87ec54a5f VTLB: Rewrite vtlb_ramRead function template
Previously the declaration didn't match the definition, so you couldn't
actually call it.
2026-06-28 16:46:13 -04:00
TJnotJT a6b1040caf GS: Update target TEX0 on a move if buffer width is increased.
Co-authored-by: refractionpcsx2
2026-06-28 21:51:10 +02:00
TheLastRar 9650c4b79a GS/HW: Tweak AF shader 2026-06-28 21:46:04 +02:00
wxvu 3f8eb5adf0 GameDB: Various fixes 2026-06-28 13:58:29 -04:00
TJnotJT 99a78f9a55 GS: Add GPU pipeline stats to OSD.
Adds vertex shader and pixel shader invocations.
2026-06-28 12:39:56 -04:00
TJnotJT c3ace64205 GS/HW: Change prefer_unused_texture parameter to prefer_reuse in GSDevice::FetchSurface().
prefer_reuse is the opposite of prefer_unused_texture, so all corresponding arguments are inverted.
2026-06-28 12:13:38 -04:00
TJnotJT 3b2c1ec6e3 GS/DX12: Fix DX12 renderpass restart optimization rebase error. 2026-06-28 12:13:38 -04:00
TJnotJT dba432639e GS/VK: Detect max supported framebuffer dimensions for null framebuffer. 2026-06-28 12:13:38 -04:00
TJnotJT 166c4491c2 GS/HW: ROV activation revisions.
Force color ROV if depth ROV is used.
Only force color/depth ROV if the draw actually uses both color/depth (fixes a bug with temporary DS for stencil being used as a ROV).
Simplify the ROV activation heuristic a bit (removed unused variables, simplify barrier counting, etc.)
2026-06-28 12:13:38 -04:00
TJnotJT d1cd5a62ed GS/HW: ROV revisions.
Use GSTexture::FeedbackTarget RTs by default (not GSTexture::ShaderWriteTarget).
Do ROV type conversion for both color and depth (if needed).
Make sure the formats for ROV actually support UAV/storage image.
Change 'PSSetUnorderedAccess' to 'PSSetROVs' for clarity.
DX12: Use enum names instead of raw constants in PSSetShaderResource().
Some string format cleanup to GL_*() macros.
VK: Do not enable ROV if FB fetch is available.
Other misc cosmetic changes such as whitespace, etc.

Co-authored-by: TellowKrinkle
2026-06-28 12:13:38 -04:00
TJnotJT b11a406519 GS: Change GSTexture::Type to GSTexture::Usage
Usage fits more cleanly with API flags.
Also separates out feedback and write usage from render target.

Co-authored-by: TellowKrinkle
2026-06-28 12:13:38 -04:00
TJnotJT c7042e1877 GS/HW: Use CreateCompatible() in texture cache to propagate correct formats.
Co-authored-by: TellowKrinkle
2026-06-28 12:13:38 -04:00
Devloon 896e0b82c2 Qt: show full game titles in grid mode.
Added UI element with new icon to toggle showing full game titles by wrapping around to the next line.
2026-06-28 11:55:18 -04:00
chaoticgd 7856757087 AudioStream: Don't compare uninitialized padding 2026-06-27 16:51:29 -04:00
chaoticgd b0ce5d7582 Debugger: Fix some uninitialized variables 2026-06-27 16:51:29 -04:00
Ziemas e23416aa92 IR3000A: Use SmallString with Zydis formatter 2026-06-27 14:26:08 -04:00
Ziemas 9a9cfca706 IR5900: Use SmallString with Zydis formatter 2026-06-27 14:26:08 -04:00
Ziemas 59feb88ef7 IR5900: fix recMemcheck to not cache loaded reg
This functions calls out of the JIT, so it will get stomped on by
something else.
2026-06-27 14:26:08 -04:00
Ziemas 247cda0e26 IR3000A: DUMP_BLOCKS: Symbolize text ptr relative 2026-06-27 14:26:08 -04:00
Ziemas 9f3233224e IR5900: DUMP_BLOCKS: Symbolize text ptr relative 2026-06-27 14:26:08 -04:00
PCSX2 Bot ef14238b4e [ci skip] Qt: Update Base Translation. 2026-06-27 09:02:47 +02:00
lightningterror 13b7345189 GS/HW: Fix bbox when using aa1.
Suggested by TJ.
2026-06-27 09:02:11 +02:00
JordanTheToaster 48ca476a2f GameSummary: Redirect to redump.info 2026-06-26 10:35:51 +02:00
JordanTheToaster 57ef8e7c25 GameDB: Various fixes 2026-06-26 10:35:51 +02:00
JordanTheToaster d09ce46700 GameDB: Add AA1 rec to the DB 2026-06-26 10:35:51 +02:00
JordanTheToaster 3afc1c2663 GameDB: Add AAT rec to the DB 2026-06-26 10:35:51 +02:00
JordanTheToaster 5821762870 ImGuiOverlay: Add ROV to GPU status 2026-06-26 10:35:51 +02:00
JordanTheToaster 86b7a19f19 GS/DX11/DX12: Report ROV support in log 2026-06-26 10:35:51 +02:00
PCSX2 Bot cc85cef17c [ci skip] Qt: Update Base Translation. 2026-06-25 20:54:38 -04:00
SternXD 5f08f523c2 Qt: Add sorting to memory card list 2026-06-25 21:04:04 +02:00
KamFretoZ b612959682 Qt/GameListBackground: Dont keep re-encoding frames 2026-06-25 21:03:07 +02:00
KamFretoZ aea83d5ece Qt/GameListBackground: Make focus detection less agressive
So that custom background can still play when child window is focused
2026-06-25 21:03:07 +02:00
KamFretoZ 07aa5786e5 Qt/GameListBackground: Small fixes
fix possibly wrong DPR calculation on HiDPI display and add processBackgroundFrame() to showEvent
2026-06-25 21:03:07 +02:00
KamFretoZ 5bd70aff90 Qt/GameListBackground: Make highlight semi-transparent
and a semi-transparent backdrop to "No Game Detected" screen
2026-06-25 21:03:07 +02:00
KamFretoZ 22b8d52311 Qt/GameListBackground: Auto adjust gamelist type icon color 2026-06-25 21:03:07 +02:00
KamFretoZ ee6c7e6286 Qt/GameListBackground: Auto adjust gamelist text color 2026-06-25 21:03:07 +02:00
lightningterror 66ea4c4967 GS/DX11: Backport ds as rt from GL for depth feedback.
Doing gpu depth copies is quite slower on dx11, so let's
use the ds as rt behavior from GL which would allow us
to treat them as rt copies instead which are faster.
2026-06-25 20:56:58 +02:00
lightningterror a6769818fd GS/HW: DATE setup changes.
DATE one can run on complex alpha test if there's no overlap.
Make sure DATE one doesn't run if complex alpha test is enabled and there's overlap.
Enable DATE barrier on complex alpha test if there's overlap.
2026-06-24 16:02:45 +02:00
refractionpcsx2 95535215aa GS/TC: Use ValidOverlaps check for exact Tex is RT matches 2026-06-23 03:13:35 +02:00
TJnotJT eadb46c5ac GS/DX12: Remove unnecessary UAV state and simplify texture unbinding. 2026-06-23 02:59:46 +02:00
PCSX2 Bot b2b7943dbe [ci skip] PAD: Update to latest controller database. 2026-06-22 14:48:03 -04:00
dependabot[bot] a0a261db50 Bump actions/checkout in the ci-deps group across 1 directory
Bumps the ci-deps group with 1 update in the / directory: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: ci-deps
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 10:26:36 -04:00
lightningterror 8e73dea7e2 GS/GL: Fix recent aa1 shader regressions.
Line was accidentally removed and macro typo.
2026-06-21 01:17:52 +02:00
TJnotJT e2a3670d65 GS/HW: Adjust line AA1 blur with upscaling. 2026-06-20 22:09:33 +02:00
jasaaved 342db51523 FullscreenUI: Fix controller navigation breaking after Big Picture Mode window resized
If Big Picture mode's window is resized too greatly, the window's NavRectRel are stale and controller navigation breaks. This also happens when toggling fullscreen.

Now we force a nav reinit when resizing.
2026-06-19 23:40:42 +02:00
chaoticgd 414f1660ed Memory: Fix typo in SysMemory::DumpMemoryMap 2026-06-19 16:43:10 -04:00
PCSX2 Bot cd9530eec3 [ci skip] Qt: Update Base Translation. 2026-06-16 02:41:59 +02:00
PCSX2 Bot 53675cf5ce [ci skip] PAD: Update to latest controller database. 2026-06-15 19:42:12 +02:00
Bobby Smith e0566546c6 OSD: Include "Show GPU Debug Info" when using the "De/Select All" buttons 2026-06-15 18:41:24 +02:00
TJnotJT 6c4a8efe25 QT/FSUI: Set ROV default off and move the settings to Graphics>Rendering.
ROV may have negative performance impacts on some games/systems so allow users to opt in. Also it needs further revision/refinement.
2026-06-15 18:31:08 +02:00
lightningterror a8db6587cb Qt: Disable VK Rov barrier toggle on other renderers. 2026-06-15 18:28:55 +02:00
PCSX2 Bot 1d8fb3d407 [ci skip] Qt: Update Base Translation. 2026-06-13 20:29:29 -04:00
Oleg Tolmatcev 2d09d53805 Misc: clean up COM code 2026-06-13 15:40:44 -04:00
102 changed files with 5692 additions and 4138 deletions
@@ -11,7 +11,7 @@ jobs:
name: "Update Base Translation"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Update Base Translation
run: ./.github/workflows/scripts/common/update_base_translation.sh
@@ -9,7 +9,7 @@ jobs:
if: github.repository == 'PCSX2/pcsx2'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Get Latest DB and Prepare DB File
run: |
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install Packages
run: |
+2 -2
View File
@@ -51,7 +51,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
set-safe-directory: ${{ env.GITHUB_WORKSPACE }}
# 10 here, since the odds of having 10 untagged commits in a row should be slim to none
@@ -163,7 +163,7 @@ jobs:
if: always() && needs.build_linux.result == 'failure' && inputs.publish == true
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Push Discord Webhook
env:
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
# actions/checkout elides tags, fetch them primarily for releases
- name: Fetch Tags
+2 -2
View File
@@ -35,7 +35,7 @@ jobs:
outputs:
new_tag: ${{ steps.tag_version.outputs.new_tag }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
# Docs - https://github.com/mathieudutour/github-tag-action
- name: Bump Version and Push Tag
@@ -176,7 +176,7 @@ jobs:
name: "Upload Artifacts"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Prepare Artifact Folder
run: mkdir ./ci-artifacts/
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: windows-2025-vs2026
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Verify VS Project Files
run: .github\workflows\scripts\windows\validate-vs-filters.ps1
+1 -1
View File
@@ -56,7 +56,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Configure MSBuild Clang Version
if: inputs.configuration != 'CMake'
+184 -70
View File
@@ -201,7 +201,6 @@ PAPX-90203:
name-en: "Gran Turismo 2000 [Trial]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Fixes missing lens flare and intensity.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
@@ -228,7 +227,8 @@ PAPX-90207:
name-en: "Gran Turismo 3 - A-Spec - Autobacs Gentei Replay Theater"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90208:
name: "GRAN TURISMO 3 - A-Spec - リプレイシアター"
@@ -236,7 +236,8 @@ PAPX-90208:
name-en: "Gran Turismo 3 - A-Spec - Replay Theater"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90209:
name: "GRAN TURISMO 3 - A-Spec - Netz TOYOTA - リプレイシアターディスク"
@@ -244,7 +245,8 @@ PAPX-90209:
name-en: "Gran Turismo 3 - A-Spec - Netz TOYOTA - Replay Theater Disc"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90210:
name: "やっぱ RPGでしょ。 [オリジナルムービーディスク]"
@@ -420,9 +422,8 @@ PAPX-90504:
name-en: "Gran Turismo Concept - Airtrek Turbo Special Edition [Trial]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90505:
name: "2002 夏のオススメソフト おためしDisc"
@@ -449,14 +450,22 @@ PAPX-90507:
name-en: "Official Demo Disc 2003"
region: "NTSC-J"
PAPX-90508:
name: "GRAN TURISMO 4 - LUPO CUP Training Version"
name-sort: "ぐらんつーりすも 4 るぽ かっぷ とれいにんぐ ばーじょん"
name-en: "GRAN TURISMO 4 - LUPO CUP Training Version"
name: "GRAN TURISMO Concept - LUPO CUP Training Version"
name-sort: "ぐらんつーりすも こんせぷと るぽ かっぷ とれいにんぐ ばーじょん"
name-en: "Gran Turismo Concept - LUPO CUP Training Version"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90509:
name: "GRAN TURISMO Concept - LUPO CUP Training Version 2"
name-sort: "ぐらんつーりすも こんせぷと るぽ かっぷ とれいにんぐ ばーじょん 2"
name-en: "Gran Turismo Concept - LUPO CUP Training Version 2"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90511:
name: "SIREN [体験版]"
@@ -470,14 +479,12 @@ PAPX-90511:
PAPX-90512:
name: "GRAN TURISMO 4 - TOYOTA Prius [体験版]"
name-sort: "ぐらんつーりすも 4 - とよた ぷりうす [たいけんばん]"
name-en: "GRAN TURISMO 4 - TOYOTA Prius [Trial]"
name-en: "Gran Turismo 4 - TOYOTA Prius [Trial]"
region: "NTSC-J"
clampModes:
vuClampMode: 2 # Text in GT mode works.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90514:
name: "冬のオススメソフト おためしDISC"
@@ -531,6 +538,8 @@ PAPX-90523:
name-sort: "ぐらんつーりすも 4 - おんらいんじっけんばーじょん"
name-en: "Gran Turismo 4 - Online Test Version"
region: "NTSC-J"
clampModes:
vuClampMode: 2 # Text in GT mode works.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
@@ -680,20 +689,26 @@ PBPX-95501:
PBPX-95502:
name: "GRAN TURISMO 3 - A-Spec [本体同梱版]"
name-sort: "ぐらんつーりすも 3 - A-Spec [ほんたいどうこんばん]"
name-en: "GRAN TURISMO 3 - A-Spec [PS2 Bundle]"
name-en: "Gran Turismo 3 - A-Spec [PS2 Bundle]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCPS-15009"
PBPX-95503:
name: "Gran Turismo 3 - A-Spec [PS2 Bundle]"
region: "NTSC-U"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95503"
- "SCUS-97102"
- "SCUS-97512"
PBPX-95506:
name: "PlayStation 2 - Demo Disc 2001"
region: "PAL-M5"
@@ -752,18 +767,18 @@ PBPX-95523:
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
# vuClampMode = 2 Text in GT mode works.
PBPX-95524:
name: "Gran Turismo 4 Prologue [PlayStation 2 Racing Pack]"
region: "NTSC-C"
compat: 5
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
# vuClampMode = 2 Text in GT mode works.
PBPX-95525:
name: "ファイナルファンタジーⅫ [本体同梱版]"
name-sort: "ふぁいなるふぁんたじー 12 [ほんたいどうこんばん]"
@@ -772,7 +787,7 @@ PBPX-95525:
PBPX-95601:
name: "GRAN TURISMO 4 [本体同梱版]"
name-sort: "ぐらんつーりすも 4 [ほんたいどうこんばん]"
name-en: "GRAN TURISMO 4 [PS2 Bundle]"
name-en: "Gran Turismo 4 [PS2 Bundle]"
region: "NTSC-J"
compat: 5
clampModes:
@@ -783,6 +798,7 @@ PBPX-95601:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -826,9 +842,11 @@ PCPX-96306:
PCPX-96309:
name: "GRAN TURISMO 3 Netz TOYOTA [Demo]"
name-sort: "ぐらんつーりすも 3 ねっつ とよた [Demo]"
name-en: "GRAN TURISMO 3 Netz TOYOTA [Demo]"
name-en: "Gran Turismo 3 Netz TOYOTA [Demo]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Fixes missing lens flare and intensity.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-96310:
name: "エクストリーム・レーシング SSX [体験版]"
@@ -845,7 +863,8 @@ PCPX-96311:
name-en: "Gran Turismo 3 Trial Disk Volume 1"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Fixes missing lens flare and intensity.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-96312:
name: "GRAN TURISMO 3 - A-Spec - [オートバックス店頭試遊ディスク]"
@@ -853,7 +872,8 @@ PCPX-96312:
name-en: "Gran Turismo 3 - A-Spec - Autobacs Tentou Shiyuu Disc"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Fixes missing lens flare and intensity.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-96314:
name: "スカイオデッセイ [体験版]"
@@ -986,6 +1006,8 @@ PCPX-96609:
name-en: "Gran Turismo 3 - A-Spec - Tentou Shiyuu Disc Vol. 2"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-96610:
name: "見る見る 2001年2月度受注号"
@@ -1061,7 +1083,8 @@ PCPX-96624:
name-en: "Gran Turismo - Concept 2001 Tokyo"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-96625:
name: "プレプレ2 VOLUME.4"
@@ -1109,14 +1132,13 @@ PCPX-96633:
name-en: "Play-Pre 2 Volume 7 - 2003 April - CM Collection"
region: "NTSC-J"
PCPX-96634:
name: "GRAN TURISMO - SUBARU ドライビングシミュレーターVer."
name: "GRAN TURISMO - SUBARU ドライビングシミュレーターVersion"
name-sort: "ぐらんつーりすも すばるどらいびんぐしみゅれーたーばーじょん"
name-en: "Gran Tourismo - SUBARU Driving Simulator ver."
name-en: "Gran Turismo - SUBARU Driving Simulator Version"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-96635:
name: "プレプレ2 VOLUME.8"
@@ -1151,7 +1173,7 @@ PCPX-96646:
PCPX-96649:
name: "GRAN TURISMO 4 [体験版]"
name-sort: "ぐらんつーりすも 4 [たいけんばん]"
name-en: "Gran Tourismo 4 [Trial]"
name-en: "Gran Turismo 4 [Trial]"
region: "NTSC-J"
compat: 5
clampModes:
@@ -1204,6 +1226,9 @@ PCPX-96660:
clampModes:
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PCPX-98017:
name: "ラチェット&クランク4th ギリギリ銀河のギガバトル [体験版]"
@@ -1668,9 +1693,11 @@ SCAJ-20066:
compat: 5
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -1960,6 +1987,7 @@ SCAJ-20109:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
memcardFilters:
- "SCAJ-20109"
- "SCAJ-20052"
@@ -2421,6 +2449,9 @@ SCAJ-20170:
clampModes:
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCAJ-20171:
name: "絶体絶命都市2 - 凍てついた記憶たち"
@@ -2721,6 +2752,7 @@ SCAJ-30006:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -2755,6 +2787,7 @@ SCAJ-30008:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -3321,9 +3354,8 @@ SCED-51352:
name: "Gran Turismo - Nissan Micra Edition [Demo]"
region: "PAL-E"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCED-51359:
name: "Official PlayStation 2 Magazine Demo 27"
@@ -3890,9 +3922,9 @@ SCED-52455:
region: "PAL-E"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
# vuClampMode = 2 Text in GT mode works.
SCED-52461:
name: "SingStar [Press Kit]"
region: "PAL-E"
@@ -4872,7 +4904,8 @@ SCES-50294:
region: "PAL-M5"
compat: 5
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCES-50295:
name: "Dark Cloud"
@@ -5142,6 +5175,8 @@ SCES-50858:
region: "PAL-M6"
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "SCES-50858"
@@ -5838,7 +5873,8 @@ SCES-52438:
compat: 5
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "SCES-51719"
@@ -5857,6 +5893,7 @@ SCES-52456:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
memcardFilters: # Reads Ratchet 1 & 2 data.
- "SCES-52456"
- "SCES-51607"
@@ -6195,6 +6232,9 @@ SCES-53372:
clampModes:
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCES-53397:
name: "SingStar - Popworld Events Code"
@@ -7442,6 +7482,8 @@ SCKA-20029:
name: "Gran Turismo Concept - 2002 Tokyo-Seoul [PlayStation 2 BigHit Series]" # No listed Korean name on ReDump
region: "NTSC-K"
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCKA-20030:
name: "슬라이 쿠퍼 - 전설의 비법서를 찾아서 [PlayStation 2 BigHit Series]"
@@ -7507,6 +7549,7 @@ SCKA-20037:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
memcardFilters:
- "SCKA-20037"
- "SCKA-20011"
@@ -8446,9 +8489,8 @@ SCPM-85301:
name-en: "Gran Turismo Concept - Copen Special Edition [Demo]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPM-85302:
name: "みんなのGOLF オンライン"
@@ -8783,8 +8825,12 @@ SCPS-15009:
name-en: "Gran Turismo 3 - A-Spec"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCPS-15009"
SCPS-15010:
name: "GRAN TURISMO Concept 2001 Tokyo"
name-sort: "ぐらんつーりすも こんせぷと 2001 Tokyo"
@@ -8792,7 +8838,8 @@ SCPS-15010:
region: "NTSC-J"
compat: 5
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-15011:
name: "EXTERMINATION"
@@ -9132,9 +9179,11 @@ SCPS-15055:
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -9387,6 +9436,7 @@ SCPS-15084:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
memcardFilters:
- "SCPS-15084"
- "SCPS-15056"
@@ -9603,6 +9653,9 @@ SCPS-15105:
clampModes:
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-15106:
name: "SIREN2"
@@ -9769,6 +9822,7 @@ SCPS-17001:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -9796,6 +9850,7 @@ SCPS-17008:
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-17009:
name: "NIKE/ GRAN TURISMO Limited Edition [9inch]"
@@ -9805,6 +9860,7 @@ SCPS-17009:
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-17010:
name: "NIKE/ GRAN TURISMO Limited Edition [10inch]"
@@ -9814,6 +9870,7 @@ SCPS-17010:
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-17011:
name: "NIKE/ GRAN TURISMO Limited Edition [11inch]"
@@ -9823,6 +9880,7 @@ SCPS-17011:
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-17013:
name: "ローグギャラクシー ディレクターズカット"
@@ -9980,7 +10038,8 @@ SCPS-19208:
name-en: "Gran Turismo - Concept 2001 Tokyo [PlayStation2 the Best]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-19209:
name: "ぼくのなつやすみ2 海の冒険篇 [PlayStation2 the Best]"
@@ -10056,6 +10115,7 @@ SCPS-19252:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -10120,9 +10180,11 @@ SCPS-19304:
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95502"
- "SCAJ-20066"
- "SCAJ-30006"
- "SCAJ-30007"
@@ -10184,6 +10246,7 @@ SCPS-19309:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
SCPS-19310:
name: "ラチェット&クランク [PlayStation2 the Best]"
name-sort: "らちぇっとあんどくらんく [PlayStation2 the Best]"
@@ -10364,6 +10427,9 @@ SCPS-19324:
clampModes:
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-19325:
name: "サルゲッチュ ミリオンモンキーズ [PlayStation2 the Best]"
@@ -10585,7 +10651,8 @@ SCPS-55005:
name-en: "Gran Turismo - Concept 2001 Tokyo"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-55006:
name: "ワイルドアームズ アドヴァンスドサード"
@@ -10598,10 +10665,11 @@ SCPS-55006:
SCPS-55007:
name: "GRAN TURISMO 3 - A-Spec"
name-sort: "ぐらんつーりすも 3 - A-Spec"
name-en: "GRAN TURISMO 3 - A-Spec"
name-en: "Gran Turismo 3 - A-Spec"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-55008:
name: "サンダーストライカー"
@@ -10934,6 +11002,8 @@ SCPS-55902:
name-en: "Gran Turismo - Concept 2002 Tokyo-Geneva"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-55903:
name: "GRAN TURISMO - Concept 2002 Tokyo-Geneva"
@@ -10941,6 +11011,8 @@ SCPS-55903:
name-en: "Gran Turismo - Concept 2002 Tokyo-Geneva"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-56001:
name: "이코"
@@ -10978,6 +11050,8 @@ SCPS-56005:
name: "Gran Turismo Concept - 2002 Tokyo-Seoul" # No listed Korean name on ReDump
region: "NTSC-K"
gsHWFixes:
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-56006:
name: "철권 "
@@ -11058,7 +11132,8 @@ SCPS-72001:
name-en: "Gran Turismo 3 - A-Spec [MEGA HITS!]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCPS-72002:
name: "みんなのGOLF 3 [MEGA HITS!]"
@@ -11098,7 +11173,9 @@ SCUS-90682:
clampModes:
vuClampMode: 2 # Text in GT mode works.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCUS-94346:
name: "SingStar - Latino"
@@ -11124,8 +11201,13 @@ SCUS-97102:
region: "NTSC-U"
compat: 5
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95503"
- "SCUS-97102"
- "SCUS-97512"
SCUS-97104:
name: "ATV Offroad Fury"
region: "NTSC-U"
@@ -11186,7 +11268,8 @@ SCUS-97115:
name: "Gran Turismo 3 - A-Spec [Demo]"
region: "NTSC-U"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCUS-97116:
name: "Kiosk Disc 2.1"
@@ -11621,7 +11704,8 @@ SCUS-97219:
name: "Gran Turismo 3 - A-Spec - Nissan 350Z Edition"
region: "NTSC-U"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "SCUS-97219"
@@ -11987,6 +12071,7 @@ SCUS-97328:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters: # Allows car imports from GT3 or something.
- "PBPX-95503"
- "SCUS-97328"
- "SCUS-97436"
- "SCUS-97102"
@@ -12069,6 +12154,7 @@ SCUS-97353:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
memcardFilters:
- "SCUS-97353"
- "SCUS-97268"
@@ -12190,8 +12276,8 @@ SCUS-97384:
region: "NTSC-U"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCUS-97392:
name: "NBA '06 featuring The Life Vol.1 [Demo]"
@@ -12302,6 +12388,7 @@ SCUS-97411:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
SCUS-97412:
name: "Jak 3 [Demo]"
region: "NTSC-U"
@@ -12325,6 +12412,7 @@ SCUS-97413:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
SCUS-97414:
name: "EyeToy - AntiGrav"
region: "NTSC-U"
@@ -12427,6 +12515,7 @@ SCUS-97436:
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
memcardFilters:
- "PBPX-95503"
- "SCUS-97328"
- "SCUS-97436"
- "SCUS-97102"
@@ -12774,6 +12863,9 @@ SCUS-97502:
clampModes:
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCUS-97503:
name: "MLB '06 - The Show [Demo]"
@@ -12825,10 +12917,12 @@ SCUS-97512:
name: "Gran Turismo 3 - A-Spec [Greatest Hits]"
region: "NTSC-U"
memcardFilters:
- "SCUS-97512"
- "PBPX-95503"
- "SCUS-97102"
- "SCUS-97512"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCUS-97513:
name: "Ratchet & Clank 2 - Going Commando [Greatest Hits]"
@@ -12884,6 +12978,7 @@ SCUS-97518:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
memcardFilters:
- "SCUS-97518"
- "SCUS-97513"
@@ -13034,7 +13129,9 @@ SCUS-97563:
clampModes:
vuClampMode: 2 # Text in GT mode works.
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
SCUS-97564:
name: "Jampack Demo Disc Vol.15 [T-Rated]"
@@ -18668,6 +18765,8 @@ SLES-51713:
SLES-51714:
name: "BCV - Battle Construction Vehicles"
region: "PAL-E"
gsHWFixes:
recommendedHWAA1: 1 # Fixes line thickness on vehicles and buildings.
SLES-51715:
name: "The Seed - War Zone"
name-sort: "Seed, The - War Zone"
@@ -20958,6 +21057,9 @@ SLES-52584:
name: "Burnout 3 - Takedown"
region: "PAL-M4"
compat: 5
memcardFilters: # Used for storage of network information on the memory card.
- "SLES-52584"
- "PSCD-20001"
clampModes:
vuClampMode: 3 # Fixes buggy lighting in the garage.
gsHWFixes:
@@ -22075,10 +22177,10 @@ SLES-52939:
name: "Airborne Troops - Countdown to D-Day"
region: "PAL-M4"
SLES-52940:
name: "S.L.A.I. Steel Lancer Arena International"
name: "S.L.A.I. - Steel Lancer Arena International"
region: "PAL-M3"
gsHWFixes:
halfPixelOffset: 4 # Fixes double image and aligns glow effects.
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
SLES-52941:
name: "Gungrave - Overdose"
region: "PAL-M3"
@@ -45975,12 +46077,12 @@ SLPM-65790:
nativeScaling: 4 # Fixes post lighting.
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
SLPM-65791:
name: "S.L.A.I -STEEL LANCER ARENA INTERNATIONAL-"
name: "S.L.A.I. -STEEL LANCER ARENA INTERNATIONAL-"
name-sort: "すれい -すてぃーる らんさー ありーな いんたーなしょなる-"
name-en: "S.L.A.I. - Steel Lancer Arena International"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 4 # Fixes double image and aligns glow effects.
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
SLPM-65793:
name: "SSX3 [EA BEST HITS]"
name-sort: "SSX3 [EA BEST HITS]"
@@ -57490,6 +57592,8 @@ SLPS-25004:
name-en: "Kensetsu Juuki Kenka Battle - Buchigire Kongou!!"
region: "NTSC-J"
compat: 5
gsHWFixes:
recommendedHWAA1: 1 # Fixes line thickness on vehicles and buildings.
SLPS-25005:
name: "ロックンメガステージ"
name-sort: "ろっくんめがすてーじ"
@@ -59868,6 +59972,8 @@ SLPS-25394:
name-sort: "あなざーせんちゅりーずえぴそーど"
name-en: "Another Century's Episode"
region: "NTSC-J"
gsHWFixes:
textureInsideRT: 1 # Fixes broken effect rendering.
SLPS-25395:
name: "センチメンタルプレリュード"
name-sort: "せんちめんたるぷれりゅーど"
@@ -63979,6 +64085,8 @@ SLPS-73227:
name-sort: "あなざーせんちゅりーずえぴそーど [PlayStation2 the Best]"
name-en: "Another Century's Episode [PlayStation2 the Best]"
region: "NTSC-J"
gsHWFixes:
textureInsideRT: 1 # Fixes broken effect rendering.
SLPS-73228:
name: "風雲 幕末伝 [PlayStation2 the Best]"
name-sort: "ふううんばくまつでん [PlayStation2 the Best]"
@@ -69511,11 +69619,11 @@ SLUS-20968:
name: "Karaoke Revolution Volume 2"
region: "NTSC-U"
SLUS-20969:
name: "S.L.A.I. - Steel Lancer Arena International - Phantom Crash"
name: "S.L.A.I. - Steel Lancer Arena International"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 4 # Fixes double image and aligns glow effects.
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
SLUS-20970:
name: "Rumble Roses"
region: "NTSC-U"
@@ -70060,6 +70168,9 @@ SLUS-21050:
name: "Burnout 3 - Takedown"
region: "NTSC-U"
compat: 5
memcardFilters: # Used for storage of network information on the memory card.
- "SLUS-21050"
- "PSCD-10088"
clampModes:
vuClampMode: 3 # Fixes buggy lighting in the garage.
gsHWFixes:
@@ -76042,7 +76153,7 @@ SLUS-29132:
name: "S.L.A.I. - Steel Lancer Arena International - Phantom Crash [Public Beta Vol.1.0]"
region: "NTSC-U"
gsHWFixes:
halfPixelOffset: 4 # Fixes double image and aligns glow effects.
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
SLUS-29133:
name: "Namco Transmission Demo Disc Vol.2"
region: "NTSC-U"
@@ -76490,6 +76601,7 @@ TCES-52456:
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 1 # Fixes light blooms.
autoFlush: 2 # Helps fix misaligned bloom.
recommendedAccurateAlphaTest: 1 # Fixes shadows and glasses alpha.
TCES-52582:
name: "Everybody's Golf 4 [Beta Trial Code]"
region: "PAL-E"
@@ -76842,6 +76954,8 @@ TLES-52781:
TLES-52940:
name: "S.L.A.I. - Steel Lancer Arena International Beta Trial Code"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 5 # Fixes double image and aligns glow effects.
TLES-53544:
name: "Pro Evolution Soccer 5 Beta Trial Code"
region: "PAL-E"
+9
View File
@@ -941,6 +941,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000e30500008106000000010000,Austgame GameCube Adapter,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:+a4,leftx:a0,lefty:a1,misc3:b5,misc4:b6,rightshoulder:b4,righttrigger:-a4,rightx:a2,righty:a3,start:b7,x:b1,y:b3,platform:Mac OS X,
030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
030000008a3500000201000000010000,Backbone One,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:Mac OS X,
030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
@@ -1252,12 +1253,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00001230000011010000,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:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001330000011010000,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:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00001230000000010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001260000011010000,8BitDo Ultimate 2,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,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
03000000c82d00000b31000014010000,8BitDo Ultimate 2,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
05000000c82d00001260000001000000,8BitDo Ultimate 2,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,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
03000000c82d00000a31000014010000,8BitDo Ultimate 2C,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,
03000000c82d00001d30000011010000,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:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00001b30000001000000,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:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001530000011010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001630000011010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001730000011010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
06000000c82d00000320000007010000,8BitDo Ultimate Wired Controller for Xbox,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,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,
05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,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,
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
@@ -1279,6 +1284,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000020500000913000010010000,Anbernic RG P01,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,
03000000373500000710000010010000,Anbernic RG P01,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,
05000000373500004610000001000000,Anbernic RG P01,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
19000000010000000100000000010000,Anbernic RG28XX Controller,a:b4,b:b3,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b7,misc1:b1,rightshoulder:b8,leftstick:b12,rightstick:b13,start:b10,x:b5,y:b6,platform:Linux,
03000000190e00000110000010010000,Aquaplus Piece,a:b1,b:b0,back:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b2,platform:Linux,
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@@ -1351,6 +1357,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ac0500007a05000011010000,GameSir G5,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:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500009710000001020000,GameSir Kaleid Flux,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500005810000001020000,GameSir K1,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000ac0500001a06000011010000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000373500000410000044010000,GameSir T4 Kaleid,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,
03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1449,6 +1456,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
03000000314100001935000000010000,LeadJoy Xeno Plus,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:a4,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e000001f5000010010000,Logic3 Gamepad,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,
030000006d040000d1ca000000000000,Logitech Chillstream,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,
030000006d040000d1ca000011010000,Logitech Chillstream,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,
030000006d04000016c2000010010000,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:Linux,
@@ -1621,6 +1629,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,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,
03000000d62000006520000002010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000017000010010000,PS SS N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
+62 -54
View File
@@ -214,7 +214,7 @@ struct PS_OUTPUT_REAL
#if PS_RETURN_DEPTH
// In DX12 we do depth feedback loops with a color copy.
#if SW_DEPTH && PS_NO_COLOR1 && DX12
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
#if NUM_RTS > 0
float depth_color : SV_Target1;
#else
@@ -290,6 +290,12 @@ cbuffer cb1
float4x4 DitherMatrix;
float ScaledScaleFactor;
float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
};
float4 RtLoad(int2 xy)
@@ -355,23 +361,28 @@ bool2 nan_or_inf(float2 xy)
float4 sample_c_af(float2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = any(nan_or_inf(uv)) ? float2(0, 0) : uv;
uv = any(nan_or_inf(uv)) ? float2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
float2 sz;
Texture.GetDimensions(sz.x, sz.y);
float2 dX = ddx(uv) * sz;
float2 dY = ddy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(nan_or_inf(dX) | nan_or_inf(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -379,42 +390,49 @@ float4 sample_c_af(float2 uv, float uv_w)
float A = dX.y * dX.y + dY.y * dY.y;
float B = -2 * (dX.x * dX.y + dY.x * dY.y);
float C = dX.x * dX.x + dY.x * dY.x;
float f = (dX.x * dY.y - dY.x * dX.y);
float F = f * f;
float p = A - C;
float q = A + C;
float t = sqrt(p * p + B * B);
float sqrt_num_plus = sqrt(F * (t + p));
float sqrt_num_minus = sqrt(F * (t - p));
float inv_sqrt_denom_plus = rsqrt(t * (q + t));
float inv_sqrt_denom_minus = rsqrt(t * (q - t));
float signB = sign(B);
float2 new_dX = float2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrt_num_plus * inv_sqrt_denom_plus,
sqrt_num_minus * inv_sqrt_denom_plus * signB
);
float2 new_dY = float2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrt_num_minus * inv_sqrt_denom_minus * -signB,
sqrt_num_plus * inv_sqrt_denom_minus
);
d_inf_nan = any(nan_or_inf(new_dX) | nan_or_inf(new_dY));
if (!d_inf_nan)
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
float2 aniso_line;
if (length_major <= 1.0f)
{
// A zero length_major would result in NaN Lod and break sampling.
@@ -422,57 +440,44 @@ float4 sample_c_af(float2 uv, float uv_w)
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = float2(0, 0);
aniso_line = float2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
float2 aniso_line_dir = float2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
float2 aniso_line_dir = is_major_x ? dX : dY;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_ANISOTROPIC_FILTERING)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_ANISOTROPIC_FILTERING;
length_lod = length_major / PS_ANISOTROPIC_FILTERING;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, PS_ANISOTROPIC_FILTERING);
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
#if PS_AUTOMATIC_LOD == 1
float lod = log2(length_lod);
#elif PS_MANUAL_LOD == 1
float lod = manual_lod(uv_w);
#else
float lod = 0; // No Lod
float lod = 0.0f; // No Lod
#endif
float4 colour;
if (aniso_ratio == 1.0f)
colour = Texture.SampleLevel(TextureSampler, uv, lod);
else
{
float4 num = float4(0, 0, 0, 0);
for (int i = 0; i < aniso_ratio; i++)
{
float2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
float4 num = float4(0.0f, 0.0f, 0.0f, 0.0f);
float2 segment = (2.0f * aniso_line) / aniso_ratio;
int aniso_ratio_i = (int)aniso_ratio;
for (int i = 0; i < aniso_ratio_i; i++)
{
float2 d = -aniso_line + (0.5f + i) * segment;
float2 uv_sample = uv + d;
float4 sample_colour = Texture.SampleLevel(TextureSampler, uv_sample, lod);
num += sample_colour;
@@ -1362,7 +1367,12 @@ void ps_main(PS_INPUT input)
float4 C = ps_color(input);
#if PS_AA1
float cov = clamp(1.0f - abs(input.inv_cov), 0.0f, 1.0f);
#if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(input.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(input.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov;
@@ -1596,7 +1606,7 @@ if (bad)
// Depth write back
#if PS_RETURN_DEPTH
output_real.depth = input.p.z;
#if SW_DEPTH && PS_NO_COLOR1 && DX12
#if SW_DEPTH && PS_NO_COLOR1 && PS_DEPTH_FEEDBACK_SUPPORT == 2
// Output color clone for feedback.
output_real.depth_color = input.p.z;
#endif
@@ -1632,7 +1642,7 @@ cbuffer cb0
float2 TextureOffset;
float2 PointSize;
uint MaxDepth;
uint _cb0_pad0;
float LineAA1Width;
};
#ifdef DX12
@@ -1875,11 +1885,9 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
// Use bottom minus top for delta regardless of which vertex we are expanding.
float2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
float2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
float2 line_expand = float2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
float2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? float2(0.0f, 2.0f) : float2(2.0f, 0.0f);
#if VS_EXPAND == VS_EXPAND_LINE_AA1
line_expand *= 2.0f * LineAA1Width;
#endif
float2 line_width = (line_expand * PointSize) / 2;
float2 offset = is_right ? line_width : -line_width;
+56 -46
View File
@@ -93,6 +93,13 @@ layout(std140, binding = 0) uniform cb21
float ScaledScaleFactor;
float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
};
in SHADER
@@ -213,22 +220,27 @@ float manual_lod(float uv_w)
vec4 sample_c_af(vec2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0, 0) : uv;
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
vec2 sz = textureSize(TextureSampler, 0);
vec2 dX = dFdx(uv) * sz;
vec2 dY = dFdy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(isinf(dX)) || any(isinf(dY)) || any(isnan(dX)) || any(isnan(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -236,38 +248,46 @@ vec4 sample_c_af(vec2 uv, float uv_w)
float A = dX.y * dX.y + dY.y * dY.y;
float B = -2 * (dX.x * dX.y + dY.x * dY.y);
float C = dX.x * dX.x + dY.x * dY.x;
float f = (dX.x * dY.y - dY.x * dX.y);
float F = f * f;
float p = A - C;
float q = A + C;
float t = sqrt(p * p + B * B);
float signB = sign(B);
float denom_plus = t * (q + t);
float denom_minus = t * (q - t);
float sqrtA = sqrt(F * (t + p));
float sqrtB = sqrt(F * (t - p));
float inv_sqrt_denom_plus = inversesqrt(denom_plus);
float inv_sqrt_denom_minus = inversesqrt(denom_minus);
vec2 new_dX = vec2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrtA * inv_sqrt_denom_plus,
sqrtB * inv_sqrt_denom_plus * signB
);
vec2 new_dY = vec2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrtB * inv_sqrt_denom_minus * -signB,
sqrtA * inv_sqrt_denom_minus
);
d_inf_nan = any(isinf(new_dX)) || any(isinf(new_dY)) || any(isnan(new_dX)) || any(isnan(new_dY));
if (!d_inf_nan)
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
@@ -279,57 +299,42 @@ vec4 sample_c_af(vec2 uv, float uv_w)
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = vec2(0, 0);
aniso_line = vec2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
vec2 aniso_line_dir = vec2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
vec2 aniso_line_dir = is_major_x ? dX : dY;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_ANISOTROPIC_FILTERING)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_ANISOTROPIC_FILTERING;
length_lod = length_major / PS_ANISOTROPIC_FILTERING;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, PS_ANISOTROPIC_FILTERING);
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
#if PS_AUTOMATIC_LOD == 1
float lod = log2(length_lod);
#elif PS_MANUAL_LOD == 1
float lod = manual_lod(uv_w);
#else
float lod = 0; // No Lod
float lod = 0.0f; // No Lod
#endif
vec4 colour;
if (aniso_ratio == 1.0f)
colour = textureLod(TextureSampler, uv, lod);
else
{
vec4 num = vec4(0, 0, 0, 0);
vec4 num = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec2 segment = (2.0f * aniso_line) / aniso_ratio;
for (int i = 0; i < aniso_ratio; i++)
{
vec2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
{
vec2 d = -aniso_line + (0.5f + i) * segment;
vec2 uv_sample = uv + d;
vec4 sample_colour = textureLod(TextureSampler, uv_sample, lod);
num += sample_colour;
@@ -1250,7 +1255,12 @@ void ps_main()
vec4 C = ps_color();
#if PS_AA1
float cov = clamp(1.0f - abs(PSin.inv_cov), 0.0f, 1.0f);
#if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(PSin.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(PSin.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov;
+4 -5
View File
@@ -12,8 +12,9 @@ layout(std140, binding = 1) uniform cb20
vec2 TextureOffset;
vec2 PointSize;
uint MaxDepth;
uint pad_cb20;
float LineAA1Width;
};
#ifdef VERTEX_SHADER
@@ -323,11 +324,9 @@ void main()
// Use bottom minus top for delta regardless of which vertex we are expanding.
vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
vec2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
vec2 line_expand = vec2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
vec2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? vec2(0.0f, 2.0f) : vec2(2.0f, 0.0f);
#if VS_EXPAND == VS_EXPAND_LINE_AA1
line_expand *= 2.0f * LineAA1Width;
#endif
vec2 line_width = (line_expand * PointSize) / 2;
vec2 offset = is_right ? line_width : -line_width;
+58 -50
View File
@@ -24,7 +24,7 @@ layout(std140, set = 0, binding = 0) uniform cb0
vec2 TextureOffset;
vec2 PointSize;
uint MaxDepth;
uint pad_cb0;
float LineAA1Width;
};
layout(location = 0) out VSOutput
@@ -319,11 +319,9 @@ void main()
// Use bottom minus top for delta regardless of which vertex we are expanding.
vec2 line_delta = is_bottom ? (vtx.p.xy - other.p.xy) : (other.p.xy - vtx.p.xy);
vec2 line_vector = normalize(line_delta / VertexScale);
#if VS_EXPAND == VS_EXPAND_LINE
vec2 line_expand = vec2(line_vector.y, -line_vector.x);
#elif VS_EXPAND == VS_EXPAND_LINE_AA1
// Expand in y direction for shallow lines and x direction for steep lines.
vec2 line_expand = abs(line_vector.x) >= abs(line_vector.y) ? vec2(0.0f, 2.0f) : vec2(2.0f, 0.0f);
#if VS_EXPAND == VS_EXPAND_LINE_AA1
line_expand *= 2.0f * LineAA1Width;
#endif
vec2 line_width = (line_expand * PointSize) / 2;
vec2 offset = is_right ? line_width : -line_width;
@@ -624,6 +622,12 @@ layout(std140, set = 0, binding = 1) uniform cb1
mat4 DitherMatrix;
float ScaledScaleFactor;
float RcpScaleFactor;
float _pad0_cb1;
float _pad1_cb1;
float LineCovScale;
float _pad2_cb1;
float _pad3_cb1;
float _pad4_cb1;
};
layout(location = 0) in VSOutput
@@ -724,22 +728,27 @@ float manual_lod(float uv_w)
vec4 sample_c_af(vec2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0, 0) : uv;
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
vec2 sz = textureSize(Texture, 0);
vec2 dX = dFdx(uv) * sz;
vec2 dY = dFdy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(isinf(dX)) || any(isinf(dY)) || any(isnan(dX)) || any(isnan(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -754,31 +763,40 @@ vec4 sample_c_af(vec2 uv, float uv_w)
float q = A + C;
float t = sqrt(p * p + B * B);
float signB = sign(B);
float denom_plus = t * (q + t);
float denom_minus = t * (q - t);
float sqrtA = sqrt(F * (t + p));
float sqrtB = sqrt(F * (t - p));
float inv_sqrt_denom_plus = inversesqrt(denom_plus);
float inv_sqrt_denom_minus = inversesqrt(denom_minus);
vec2 new_dX = vec2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrtA * inv_sqrt_denom_plus,
sqrtB * inv_sqrt_denom_plus * signB
);
vec2 new_dY = vec2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrtB * inv_sqrt_denom_minus * -signB,
sqrtA * inv_sqrt_denom_minus
);
d_inf_nan = any(isinf(new_dX)) || any(isinf(new_dY)) || any(isnan(new_dX)) || any(isnan(new_dY));
if (!d_inf_nan)
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
@@ -790,57 +808,42 @@ vec4 sample_c_af(vec2 uv, float uv_w)
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = vec2(0, 0);
aniso_line = vec2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
vec2 aniso_line_dir = vec2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
vec2 aniso_line_dir = is_major_x ? dX : dY;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_ANISOTROPIC_FILTERING)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_ANISOTROPIC_FILTERING;
length_lod = length_major / PS_ANISOTROPIC_FILTERING;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, PS_ANISOTROPIC_FILTERING);
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
#if PS_AUTOMATIC_LOD == 1
float lod = log2(length_lod);
#elif PS_MANUAL_LOD == 1
float lod = manual_lod(uv_w);
#else
float lod = 0; // No Lod
float lod = 0.0f; // No Lod
#endif
vec4 colour;
if (aniso_ratio == 1.0f)
colour = textureLod(Texture, uv, lod);
else
{
vec4 num = vec4(0, 0, 0, 0);
vec4 num = vec4(0.0f, 0.0f, 0.0f, 0.0f);
vec2 segment = (2.0f * aniso_line) / aniso_ratio;
for (int i = 0; i < aniso_ratio; i++)
{
vec2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
{
vec2 d = -aniso_line + (0.5f + i) * segment;
vec2 uv_sample = uv + d;
vec4 sample_colour = textureLod(Texture, uv_sample, lod);
num += sample_colour;
@@ -1804,7 +1807,12 @@ void main()
vec4 C = ps_color();
#if PS_AA1
float cov = clamp(1.0f - abs(vsIn.inv_cov), 0.0f, 1.0f);
#if PS_AA1 == PS_AA1_LINE
// Blur only outer part of the line by scaling coverage.
float cov = clamp(LineCovScale * (1.0f - abs(vsIn.inv_cov)), 0.0f, 1.0f);
#else
float cov = clamp(1.0f - abs(vsIn.inv_cov), 0.0f, 1.0f);
#endif
#if PS_ABE
if (floor(C.a) == 128.0f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.0f * cov;
+1
View File
@@ -163,6 +163,7 @@
<ClInclude Include="WindowInfo.h" />
<ClInclude Include="YAML.h" />
<ClInclude Include="Threading.h" />
<ClInclude Include="EnumOps.h" />
<ClInclude Include="emitter\implement\avx.h" />
<ClInclude Include="emitter\implement\bmi.h" />
<ClInclude Include="emitter\instructions.h" />
+3 -3
View File
@@ -101,7 +101,7 @@ static u64 s_total_barriers = 0;
static u64 s_total_copies = 0;
static u64 s_total_uploads = 0;
static u64 s_total_readbacks = 0;
static u64 s_total_depth_copies_rov = 0;
static u64 s_total_copies_rov = 0;
static u64 s_total_draws_rov = 0;
static u64 s_total_barriers_rov = 0;
static u32 s_total_frames = 0;
@@ -298,7 +298,7 @@ void Host::BeginPresentFrame()
update_stat(GSPerfMon::TextureCopies, s_total_copies, s_last_copies);
update_stat(GSPerfMon::TextureUploads, s_total_uploads, s_last_uploads);
update_stat(GSPerfMon::Readbacks, s_total_readbacks, s_last_readbacks);
update_stat(GSPerfMon::DepthCopiesROV, s_total_depth_copies_rov, s_last_depth_copies_rov);
update_stat(GSPerfMon::TextureCopiesROV, s_total_copies_rov, s_last_depth_copies_rov);
update_stat(GSPerfMon::DrawCallsROV, s_total_draws_rov, s_last_draws_rov);
update_stat(GSPerfMon::BarriersROV, s_total_barriers_rov, s_last_barriers_rov);
@@ -917,7 +917,7 @@ void GSRunner::DumpStats()
Console.WriteLn(fmt::format("@HWSTAT@ Copies: {} (avg {})", s_total_copies, static_cast<u64>(std::ceil(s_total_copies / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Uploads: {} (avg {})", s_total_uploads, static_cast<u64>(std::ceil(s_total_uploads / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Readbacks: {} (avg {})", s_total_readbacks, static_cast<u64>(std::ceil(s_total_readbacks / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Depth Copies (ROV): {} (avg {})", s_total_depth_copies_rov, static_cast<u64>(std::ceil(s_total_depth_copies_rov / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Copies (ROV): {} (avg {})", s_total_copies_rov, static_cast<u64>(std::ceil(s_total_copies_rov / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Draws Calls (ROV): {} (avg {})", s_total_draws_rov, static_cast<u64>(std::ceil(s_total_draws_rov / static_cast<double>(s_total_drawn_frames)))));
Console.WriteLn(fmt::format("@HWSTAT@ Barriers (ROV): {} (avg {})", s_total_barriers_rov, static_cast<u64>(std::ceil(s_total_barriers_rov / static_cast<double>(s_total_drawn_frames)))));
if (s_perf_enable)
+9 -9
View File
@@ -50,15 +50,15 @@ private:
QWidget* parent;
MemoryViewType displayType = MemoryViewType::BYTE;
bool littleEndian = true;
u32 rowCount;
u32 rowVisible;
s32 rowHeight;
u32 rowCount = 0;
u32 rowVisible = 0;
s32 rowHeight = 0;
// Stuff used for selection handling
// This gets set every paint and depends on the window size / current display mode (1byte,2byte,etc)
s32 valuexAxis; // Where the hexadecimal view begins
s32 textXAxis; // Where the text view begins
s32 row1YAxis; // Where the first row starts
s32 valuexAxis = 0; // Where the hexadecimal view begins
s32 textXAxis = 0; // Where the text view begins
s32 row1YAxis = 0; // Where the first row starts
s32 segmentXAxis[16]; // Where the segments begin
bool selectedText = false; // Whether the user has clicked on text or hex
@@ -89,9 +89,9 @@ public:
{
}
u32 startAddress;
u32 selectedAddress;
s32 selectedIndex;
u32 startAddress = 0;
u32 selectedAddress = 0;
s32 selectedIndex = 0;
void UpdateStartAddress(u32 start);
void UpdateSelectedAddress(u32 selected, bool page = false);
+29 -4
View File
@@ -73,9 +73,10 @@ const char* GameListModel::getColumnName(const Column col)
return s_column_names[static_cast<int>(col)];
}
GameListModel::GameListModel(const float cover_scale, const bool show_cover_titles, const qreal dpr, QObject* parent /* = nullptr */)
GameListModel::GameListModel(const float cover_scale, const bool show_cover_titles, bool show_full_cover_titles, const qreal dpr, QObject* parent /* = nullptr */)
: QAbstractTableModel(parent)
, m_show_titles_for_covers(show_cover_titles)
, m_show_full_titles_for_covers(show_full_cover_titles)
, m_dpr{dpr}
{
loadSettings();
@@ -315,9 +316,33 @@ QVariant GameListModel::data(const QModelIndex& index, const int role) const
switch (index.column())
{
case Column_Cover:
return QSize(static_cast<int>(static_cast<float>(SIZE_HINT_WIDTH) * m_cover_scale),
static_cast<int>(static_cast<float>(m_show_titles_for_covers ? SIZE_HINT_HEIGHT_TITLES : SIZE_HINT_HEIGHT) * m_cover_scale));
{
const int cover_width = static_cast<int>(static_cast<float>(SIZE_HINT_WIDTH) * m_cover_scale);
const int cover_height = static_cast<int>(static_cast<float>(SIZE_HINT_HEIGHT) * m_cover_scale);
if (m_show_full_titles_for_covers && m_show_titles_for_covers)
{
// Find height needed for the longest title at the current font/width
const int text_width = static_cast<int>(static_cast<float>(COVER_ART_WIDTH) * m_cover_scale);
QFont font;
font.setPointSizeF(20.0f * m_cover_scale);
const QFontMetrics fm(font);
int max_text_height = fm.height();
const auto lock = GameList::GetLock();
const u32 count = GameList::GetEntryCount();
for (u32 i = 0; i < count; i++)
{
const GameList::Entry* entry = GameList::GetEntryByIndex(i);
if (!entry) continue;
const QString title = QString::fromStdString(entry->GetTitle(m_prefer_english_titles));
const QRect bound = fm.boundingRect(QRect(0, 0, text_width, 0),
Qt::TextWordWrap | Qt::AlignHCenter, title);
max_text_height = std::max(max_text_height, bound.height());
}
return QSize(cover_width, cover_height + max_text_height);
}
return QSize(cover_width, static_cast<int>(static_cast<float>(m_show_titles_for_covers ? SIZE_HINT_HEIGHT_TITLES : SIZE_HINT_HEIGHT) * m_cover_scale));
}
default:
return QVariant();
}
@@ -354,7 +379,7 @@ bool GameListModel::titlesLessThan(const int left_row, const int right_row) cons
const GameList::Entry* left = GameList::GetEntryByIndex(left_row);
const GameList::Entry* right = GameList::GetEntryByIndex(right_row);
return QtHost::LocaleSensitiveCompare(QString::fromStdString(left->GetTitleSort(m_prefer_english_titles)),
QString::fromStdString(right->GetTitleSort(m_prefer_english_titles))) < 0;
QString::fromStdString(right->GetTitleSort(m_prefer_english_titles))) < 0;
}
bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& right_index, const int column) const
+5 -1
View File
@@ -43,7 +43,7 @@ public:
static QIcon getIconForType(GameList::EntryType type);
static QIcon getIconForRegion(GameList::Region region);
GameListModel(float cover_scale, bool show_cover_titles, qreal dpr, QObject* parent = nullptr);
GameListModel(float cover_scale, bool show_cover_titles, bool show_full_cover_titles, qreal dpr, QObject* parent = nullptr);
~GameListModel();
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -63,6 +63,9 @@ public:
bool getShowCoverTitles() const { return m_show_titles_for_covers; }
void setShowCoverTitles(bool enabled) { m_show_titles_for_covers = enabled; }
bool getShowFullCoverTitles() const { return m_show_full_titles_for_covers; }
void setShowFullCoverTitles(bool enabled) { m_show_full_titles_for_covers = enabled; }
float getCoverScale() const { return m_cover_scale; }
void setCoverScale(float scale);
int getCoverArtWidth() const;
@@ -89,6 +92,7 @@ private:
float m_cover_scale = 0.0f;
std::atomic<u32> m_cover_scale_counter{0};
bool m_show_titles_for_covers = false;
bool m_show_full_titles_for_covers = false;
bool m_prefer_english_titles = false;
std::array<QString, Column_Count> m_column_display_names;
+126 -27
View File
@@ -22,7 +22,10 @@
#include <QtCore/QSortFilterProxyModel>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtGui/QColor>
#include <QtGui/QImage>
#include <QtGui/QPainter>
#include <QtGui/QPalette>
#include <QtGui/QPixmap>
#include <QtGui/QPixmapCache>
#include <QtGui/QWheelEvent>
@@ -191,6 +194,29 @@ namespace
painter->drawPixmap(rect.topLeft() + icon_top_left, highlighted_icon);
}
// Recolor the icon based on the custom background color
else if (index.column() == GameListModel::Column_Type)
{
// Fetch pixmap from cache or construct a new one.
const QColor color = option.palette.color(QPalette::Text);
const QString key = QString::fromStdString(fmt::format("type-{:016X}-{:08X}", icon.cacheKey(), color.rgba()));
QPixmap tinted_icon;
if (!QPixmapCache::find(key, &tinted_icon))
{
QImage img = icon.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
QPainter tinted_painter(&img);
tinted_painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
tinted_painter.fillRect(0, 0, img.width(), img.height(), color);
tinted_painter.end();
tinted_icon = QPixmap(QPixmap::fromImage(img));
QPixmapCache::insert(key, tinted_icon);
}
painter->drawPixmap(rect.topLeft() + icon_top_left, tinted_icon);
}
else
{
painter->drawPixmap(rect.topLeft() + icon_top_left, icon);
@@ -213,7 +239,8 @@ void GameListWidget::initialize()
{
const float cover_scale = Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f);
const bool show_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
m_model = new GameListModel(cover_scale, show_cover_titles, devicePixelRatioF(), this);
const bool show_full_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowFullCoverTitles", true);
m_model = new GameListModel(cover_scale, show_cover_titles, show_full_cover_titles, devicePixelRatioF(), this);
m_model->updateCacheSize(width(), height());
m_sort_model = new GameListSortModel(m_model);
@@ -242,6 +269,7 @@ void GameListWidget::initialize()
connect(m_ui.viewGameGrid, &QPushButton::clicked, this, &GameListWidget::showGameGrid);
connect(m_ui.gridScale, &QSlider::valueChanged, this, &GameListWidget::gridIntScale);
connect(m_ui.viewGridTitles, &QPushButton::toggled, this, &GameListWidget::setShowCoverTitles);
connect(m_ui.viewFullGridTitles, &QPushButton::toggled, this, &GameListWidget::setShowFullCoverTitles);
connect(m_ui.filterType, &QComboBox::currentIndexChanged, this, [this](int index) {
m_sort_model->setFilterType((index == 0) ? GameList::EntryType::Count : static_cast<GameList::EntryType>(index - 1));
});
@@ -322,6 +350,7 @@ void GameListWidget::initialize()
m_list_view->setFrameStyle(QFrame::NoFrame);
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
m_list_view->verticalScrollBar()->setSingleStep(15);
m_list_view->setWordWrap(show_full_cover_titles);
onCoverScaleChanged();
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
@@ -381,8 +410,14 @@ void GameListWidget::setCustomBackground()
delete m_background_movie;
m_background_movie = nullptr;
}
// Cache all frames for small images so loops don't keep re-decoding
else if (const s64 file_size = FileSystem::GetPathFileSize(path.c_str()); file_size > 0 && file_size < 64 * 1024 * 1024)
m_background_movie->setCacheMode(QMovie::CacheAll);
}
// Invalidate frame cache so the next animated frame triggers full reprocessing
m_background_last_size = QSize();
// If there is no valid background then reset fallback to default UI state
if (!m_background_movie)
{
@@ -391,6 +426,11 @@ void GameListWidget::setCustomBackground()
m_table_view->viewport()->setAutoFillBackground(true);
m_list_view->viewport()->setAutoFillBackground(true);
m_ui.stack->setPalette(QPalette());
m_background_text_color = QColor();
m_empty_widget->setPalette(QPalette());
m_empty_widget->setAutoFillBackground(false);
m_ui.stack->update();
m_table_view->setAlternatingRowColors(true);
return;
@@ -415,45 +455,79 @@ void GameListWidget::setCustomBackground()
m_background_opacity = Host::GetBaseFloatSettingValue("UI", "GameListBackgroundOpacity", 100.0f);
// Selected Custom background is valid, connect the signals and start animation in gamelist
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames, Qt::UniqueConnection);
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames);
m_ui.stack->setAutoFillBackground(false);
m_table_view->viewport()->setAutoFillBackground(false);
m_list_view->viewport()->setAutoFillBackground(false);
updateCustomBackgroundState(true);
m_background_movie->start();
updateCustomBackgroundState();
m_table_view->setAlternatingRowColors(false);
processBackgroundFrames();
}
void GameListWidget::updateCustomBackgroundState(const bool force_start)
void GameListWidget::updateCustomBackgroundState()
{
if (m_background_movie && m_background_movie->isValid())
{
if ((isVisible() && (isActiveWindow() || force_start)) && qGuiApp->applicationState() == Qt::ApplicationActive)
m_background_movie->setPaused(false);
else
m_background_movie->setPaused(true);
}
m_background_movie->setPaused(!(isVisible() && qGuiApp->applicationState() == Qt::ApplicationActive));
}
void GameListWidget::processBackgroundFrames()
{
if (m_background_movie && m_background_movie->isValid() && isVisible())
{
const int widget_width = m_ui.stack->width();
const int widget_height = m_ui.stack->height();
if (!m_background_movie || !m_background_movie->isValid() || !isVisible())
return;
if (widget_width <= 0 || widget_height <= 0)
return;
const QSize widget_size(m_ui.stack->width(), m_ui.stack->height());
if (widget_size.isEmpty())
return;
QPixmap pm = m_background_movie->currentPixmap();
const qreal dpr = devicePixelRatioF();
const int frame_number = m_background_movie->currentFrameNumber();
const qreal dpr = devicePixelRatioF();
QtUtils::resizeAndScalePixmap(&pm, widget_width, widget_height, dpr, m_background_scaling, m_background_opacity);
if (frame_number == m_background_last_frame && widget_size == m_background_last_size && qFuzzyCompare(dpr, m_background_last_dpr))
return;
m_background_pixmap = std::move(pm);
m_ui.stack->update();
}
QPixmap pm = m_background_movie->currentPixmap();
updateBackgroundTextColor(pm);
QtUtils::resizeAndScalePixmap(&pm, widget_size.width(), widget_size.height(), dpr, m_background_scaling, m_background_opacity);
m_background_pixmap = std::move(pm);
m_background_last_frame = frame_number;
m_background_last_size = widget_size;
m_background_last_dpr = dpr;
m_ui.stack->update();
}
void GameListWidget::updateBackgroundTextColor(const QPixmap& frame)
{
if (frame.isNull())
return;
const QImage sampled = frame.scaled(32, 32, Qt::IgnoreAspectRatio, Qt::FastTransformation).toImage();
const QColor average = sampled.scaled(1, 1, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).pixelColor(0, 0);
const QColor base = qApp->palette().color(QPalette::Base);
const qreal coverage = average.alphaF() * std::clamp(m_background_opacity / 100.0f, 0.0f, 1.0f);
const qreal brightness = qGray(average.rgb()) * coverage + qGray(base.rgb()) * (1.0 - coverage);
const QColor text_color = (brightness > 127.5) ? Qt::black : Qt::white;
if (m_background_text_color == text_color)
return;
m_background_text_color = text_color;
QColor highlight_color = qApp->palette().color(QPalette::Highlight);
highlight_color.setAlpha(128);
const QColor empty_backdrop_color = (text_color == Qt::black) ? QColor(255, 255, 255, 128) : QColor(0, 0, 0, 128);
QPalette palette;
palette.setColor(QPalette::Text, text_color);
palette.setColor(QPalette::WindowText, text_color);
palette.setColor(QPalette::Highlight, highlight_color);
m_ui.stack->setPalette(palette);
QPalette empty_palette;
empty_palette.setColor(QPalette::Window, empty_backdrop_color);
m_empty_widget->setPalette(empty_palette);
m_empty_widget->setAutoFillBackground(true);
}
bool GameListWidget::isShowingGameList() const
@@ -471,6 +545,11 @@ bool GameListWidget::getShowGridCoverTitles() const
return m_model->getShowCoverTitles();
}
bool GameListWidget::getShowGridFullCoverTitles() const
{
return m_model->getShowFullCoverTitles();
}
void GameListWidget::refresh(bool invalidate_cache, bool popup_on_error)
{
cancelRefresh();
@@ -499,6 +578,8 @@ void GameListWidget::cancelRefresh()
void GameListWidget::reloadThemeSpecificImages()
{
m_model->reloadThemeSpecificImages();
m_background_last_size = QSize();
processBackgroundFrames();
}
void GameListWidget::onRefreshProgress(const QString& status, int current, int total)
@@ -703,6 +784,21 @@ void GameListWidget::setShowCoverTitles(bool enabled)
emit layoutChange();
}
void GameListWidget::setShowFullCoverTitles(bool enabled)
{
if (m_model->getShowFullCoverTitles() == enabled)
return;
Host::SetBaseBoolSettingValue("UI", "GameListShowFullCoverTitles", enabled);
Host::CommitBaseSettingChanges();
m_model->setShowFullCoverTitles(enabled);
m_list_view->setWordWrap(enabled);
if (isShowingGameGrid())
m_model->refresh();
updateToolbar();
emit layoutChange();
}
void GameListWidget::updateToolbar()
{
const bool grid_view = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
@@ -718,12 +814,17 @@ void GameListWidget::updateToolbar()
QSignalBlocker sb(m_ui.viewGridTitles);
m_ui.viewGridTitles->setChecked(m_model->getShowCoverTitles());
}
{
QSignalBlocker sb(m_ui.viewFullGridTitles);
m_ui.viewFullGridTitles->setChecked(m_model->getShowFullCoverTitles());
}
{
QSignalBlocker sb(m_ui.gridScale);
m_ui.gridScale->setValue(static_cast<int>(m_model->getCoverScale() * 100.0f));
}
m_ui.viewGridTitles->setEnabled(grid_view);
m_ui.viewFullGridTitles->setEnabled(grid_view && m_model->getShowCoverTitles());
m_ui.gridScale->setEnabled(grid_view);
}
@@ -731,6 +832,7 @@ void GameListWidget::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
updateCustomBackgroundState();
processBackgroundFrames();
}
void GameListWidget::hideEvent(QHideEvent* event)
@@ -767,11 +869,8 @@ bool GameListWidget::eventFilter(QObject* watched, QEvent* event)
if (!m_background_pixmap.isNull())
{
QPainter painter(m_ui.stack);
const auto* paint_event = static_cast<QPaintEvent*>(event);
painter.save();
painter.setClipRect(paint_event->rect());
painter.drawTiledPixmap(m_ui.stack->rect(), m_background_pixmap);
painter.restore();
painter.setClipRect(static_cast<QPaintEvent*>(event)->rect());
painter.drawPixmap(0, 0, m_background_pixmap);
return true;
}
}
+9 -1
View File
@@ -9,6 +9,7 @@
#include "pcsx2/GameList.h"
#include <QtGui/QColor>
#include <QtGui/QMovie>
#include <QtGui/QPixmap>
#include <QtWidgets/QListView>
@@ -53,12 +54,14 @@ public:
void cancelRefresh();
void reloadThemeSpecificImages();
void setCustomBackground();
void updateCustomBackgroundState(const bool force_start = false);
void updateCustomBackgroundState();
void processBackgroundFrames();
void updateBackgroundTextColor(const QPixmap& frame);
bool isShowingGameList() const;
bool isShowingGameGrid() const;
bool getShowGridCoverTitles() const;
bool getShowGridFullCoverTitles() const;
std::optional<GameList::Entry> getSelectedEntry() const;
@@ -93,6 +96,7 @@ public Q_SLOTS:
void showGameList();
void showGameGrid();
void setShowCoverTitles(bool enabled);
void setShowFullCoverTitles(bool enabled);
void gridZoomIn();
void gridZoomOut();
void gridIntScale(int int_scale);
@@ -128,6 +132,10 @@ private:
QMovie* m_background_movie = nullptr;
QPixmap m_background_pixmap;
QColor m_background_text_color;
QtUtils::ScalingMode m_background_scaling = QtUtils::ScalingMode::Fit;
float m_background_opacity = 100.0f;
int m_background_last_frame = -1;
QSize m_background_last_size;
qreal m_background_last_dpr = 0.0;
};
+26
View File
@@ -120,6 +120,31 @@
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="viewFullGridTitles">
<property name="minimumSize">
<size>
<width>32</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Show Full Titles</string>
</property>
<property name="text">
<string>Show Full Titles</string>
</property>
<property name="icon">
<iconset theme="price-tag-2-line"/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="gridScale">
<property name="minimumSize">
@@ -218,6 +243,7 @@
<tabstop>viewGameList</tabstop>
<tabstop>viewGameGrid</tabstop>
<tabstop>viewGridTitles</tabstop>
<tabstop>viewFullGridTitles</tabstop>
<tabstop>gridScale</tabstop>
<tabstop>filterType</tabstop>
<tabstop>filterRegion</tabstop>
+9 -3
View File
@@ -221,11 +221,13 @@ void MainWindow::setupAdditionalUi()
}
const bool show_game_grid = Host::GetBaseBoolSettingValue("UI", "GameListGridView", false);
updateGameGridActions(show_game_grid);
const bool show_grid_cover_titles = Host::GetBaseBoolSettingValue("UI", "ShowGridCoverTitles", false);
updateGameGridActions(show_game_grid, show_grid_cover_titles);
m_game_list_widget = new GameListWidget(getContentParent());
m_game_list_widget->initialize();
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
m_ui.actionGridViewShowFullTitles->setChecked(m_game_list_widget->getShowGridFullCoverTitles());
m_ui.mainContainer->addWidget(m_game_list_widget);
updateEmulationActions(false, false, false);
@@ -543,6 +545,7 @@ void MainWindow::connectSignals()
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
connect(m_ui.actionGridViewShowFullTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowFullCoverTitles);
connect(m_ui.actionGridViewZoomIn, &QAction::triggered, m_game_list_widget, [this]() {
if (isShowingGameList())
m_game_list_widget->gridZoomIn();
@@ -554,8 +557,10 @@ void MainWindow::connectSignals()
connect(m_ui.actionGridViewRefreshCovers, &QAction::triggered, m_game_list_widget, &GameListWidget::refreshGridCovers);
connect(m_game_list_widget, &GameListWidget::layoutChange, this, [this]() {
QSignalBlocker sb(m_ui.actionGridViewShowTitles);
QSignalBlocker sb2(m_ui.actionGridViewShowFullTitles);
m_ui.actionGridViewShowTitles->setChecked(m_game_list_widget->getShowGridCoverTitles());
updateGameGridActions(m_game_list_widget->isShowingGameGrid());
m_ui.actionGridViewShowFullTitles->setChecked(m_game_list_widget->getShowGridFullCoverTitles());
updateGameGridActions(m_game_list_widget->isShowingGameGrid(), m_game_list_widget->getShowGridCoverTitles());
});
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
@@ -3667,9 +3672,10 @@ void MainWindow::updateGameDependentActions()
m_ui.actionReloadPatches->setEnabled(s_vm_valid);
}
void MainWindow::updateGameGridActions(const bool show_game_grid)
void MainWindow::updateGameGridActions(const bool show_game_grid, const bool show_grid_cover_titles)
{
m_ui.actionGridViewShowTitles->setEnabled(show_game_grid);
m_ui.actionGridViewShowFullTitles->setEnabled(show_game_grid && show_grid_cover_titles);
m_ui.actionGridViewZoomIn->setEnabled(show_game_grid);
m_ui.actionGridViewZoomOut->setEnabled(show_game_grid);
m_ui.actionGridViewRefreshCovers->setEnabled(show_game_grid);
+1 -1
View File
@@ -257,7 +257,7 @@ private:
void updateEmulationActions(bool starting, bool running, bool stopping);
void updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen);
void updateGameDependentActions();
void updateGameGridActions(const bool show_game_grid);
void updateGameGridActions(const bool show_game_grid, const bool show_grid_cover_titles);
void updateStatusBarWidgetVisibility();
void updateAdvancedSettingsVisibility();
void updateWindowTitle();
+15
View File
@@ -175,6 +175,7 @@
<addaction name="menuWindowSize"/>
<addaction name="separator"/>
<addaction name="actionGridViewShowTitles"/>
<addaction name="actionGridViewShowFullTitles"/>
<addaction name="actionGridViewZoomIn"/>
<addaction name="actionGridViewZoomOut"/>
<addaction name="actionGridViewRefreshCovers"/>
@@ -808,6 +809,20 @@
<string>Show Titl&amp;es (Grid View)</string>
</property>
</action>
<action name="actionGridViewShowFullTitles">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="icon">
<iconset theme="price-tag-2-line"/>
</property>
<property name="text">
<string>Show F&amp;ull Titles (Grid View)</string>
</property>
</action>
<action name="actionGridViewZoomIn">
<property name="icon">
<iconset theme="zoom-in-line"/>
+1 -2
View File
@@ -156,7 +156,7 @@ namespace QtUtils
if (pm->width() == dpr_expected_width &&
pm->height() == dpr_expected_height &&
pm->devicePixelRatio() == dpr &&
qFuzzyCompare(pm->devicePixelRatio(), dpr) &&
opacity == 100.0f)
{
switch (scaling_mode)
@@ -249,7 +249,6 @@ namespace QtUtils
QPixmap tileSource = pm->scaled(tileWidth, tileHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
tileSource.setDevicePixelRatio(dpr);
QBrush tileBrush(tileSource);
tileBrush.setTextureImage(tileSource.toImage());
painter.fillRect(painterRect, tileBrush);
}
break;
+1 -1
View File
@@ -364,7 +364,7 @@ void GameSummaryWidget::onSearchHashClicked()
if (m_redump_search_keyword.empty())
return;
QtUtils::OpenURL(this, fmt::format("http://redump.org/discs/quicksearch/{}", m_redump_search_keyword).c_str());
QtUtils::OpenURL(this, fmt::format("https://redump.info/discs?q={}", m_redump_search_keyword).c_str());
}
void GameSummaryWidget::onCheckWikiClicked(const std::string& serial)
+1 -1
View File
@@ -552,7 +552,7 @@
<bool>false</bool>
</property>
<property name="text">
<string>Search on Redump.org...</string>
<string>Search on Redump.info...</string>
</property>
</widget>
</item>
@@ -118,9 +118,9 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="rov">
<widget class="QCheckBox" name="rovBarriersVK">
<property name="text">
<string>Rasterizer Ordered View</string>
<string>ROV Barriers Vulkan</string>
</property>
</widget>
</item>
@@ -138,13 +138,6 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="rovBarriersVK">
<property name="text">
<string>ROV Barriers Vulkan</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
@@ -72,6 +72,13 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="rov">
<property name="text">
<string>Rasterizer Ordered View</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="enableHWFixes">
<property name="text">
<string>Manual Hardware Renderer Fixes</string>
+9 -6
View File
@@ -113,6 +113,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_hw.mipmapping, "EmuCore/GS", "hw_mipmap", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_hw.accurateAlphaTest, "EmuCore/GS", "HWAccurateAlphaTest", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_hw.hwAA1, "EmuCore/GS", "HWAA1", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_hw.rov, "EmuCore/GS", "HWROV", false);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_hw.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_hw.enableHWFixes, "EmuCore/GS", "UserHacks", false);
@@ -223,7 +224,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
//////////////////////////////////////////////////////////////////////////
// Advanced Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.rov, "EmuCore/GS", "HWROV", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useBlitSwapChain, "EmuCore/GS", "UseBlitSwapChain", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useDebugDevice, "EmuCore/GS", "UseDebugDevice", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_advanced.useDebugBlend, "EmuCore/GS", "UseDebugBlend", false);
@@ -499,6 +499,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(
m_hw.hwAA1, tr("AA1"), tr("Unchecked"), tr("Enables AA1 (PS2 antialiasing), which some games require to render correctly. This may result in a heavy performance penalty."));
dialog()->registerWidgetHelp(
m_hw.rov, tr("Rasterizer Ordered View"), tr("Unchecked"), tr("Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games with higher accuracy settings."));
dialog()->registerWidgetHelp(
m_hw.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"),
tr("Changes what filtering algorithm is used to map textures to surfaces.<br> "
@@ -759,9 +762,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
tr("Overrides the driver's heuristics for enabling exclusive fullscreen, or direct flip/scanout.<br>"
"Disallowing exclusive fullscreen may enable smoother task switching and overlays, but increase input latency."));
dialog()->registerWidgetHelp(
m_advanced.rov, tr("Rasterizer Ordered View"), tr("Checked"), tr("Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games with higher accuracy settings."));
dialog()->registerWidgetHelp(m_advanced.rovBarriersVK, tr("ROV Barriers Vulkan"), tr("Unchecked"),
tr("Forces extra barriers when using ROV with Vulkan to fix graphical issues present in some games and hardware configurations."));
@@ -1053,8 +1053,11 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
if (m_advanced.exclusiveFullscreenControl)
m_advanced.exclusiveFullscreenControl->setEnabled(is_auto || is_vk);
if (m_advanced.rov)
m_advanced.rov->setDisabled(!is_hardware || is_ogl);
if (m_hw.rov)
m_hw.rov->setDisabled(!is_hardware || is_ogl);
if (m_advanced.rovBarriersVK)
m_advanced.rovBarriersVK->setDisabled(!is_hardware || !is_vk);
// populate adapters
std::vector<GSAdapterInfo> adapters = GSGetAdapterInfo(type);
+62 -1
View File
@@ -27,6 +27,35 @@ static std::string getSlotFilenameKey(u32 slot)
return StringUtil::StdStringFromFormat("Slot%u_Filename", slot + 1);
}
namespace
{
enum MemoryCardListColumn : int
{
Name,
Type,
Formatted,
LastModified,
};
class MemoryCardListItem : public QTreeWidgetItem
{
public:
using QTreeWidgetItem::QTreeWidgetItem;
bool operator<(const QTreeWidgetItem& other) const override
{
const QTreeWidget* tree = treeWidget();
const int column = tree ? tree->sortColumn() : 0;
if (column == MemoryCardListColumn::LastModified)
{
return data(MemoryCardListColumn::LastModified, Qt::UserRole).toLongLong() <
other.data(MemoryCardListColumn::LastModified, Qt::UserRole).toLongLong();
}
return text(column).localeAwareCompare(other.text(column)) < 0;
}
};
} // namespace
MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent)
: SettingsWidget(settings_dialog, parent)
{
@@ -56,6 +85,11 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* settings_dial
connect(m_ui.convertCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::convertCard);
connect(m_ui.deleteCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::deleteCard);
loadCardListSortState();
m_ui.cardList->setSortingEnabled(true);
connect(m_ui.cardList->header(), &QHeaderView::sortIndicatorChanged, this,
&MemoryCardSettingsWidget::saveCardListSortState);
refresh();
}
@@ -340,6 +374,24 @@ void MemoryCardSettingsWidget::swapCards()
refresh();
}
void MemoryCardSettingsWidget::saveCardListSortState()
{
Host::SetBaseIntSettingValue("MemoryCardListView", "SortColumn",
m_ui.cardList->header()->sortIndicatorSection());
Host::SetBaseBoolSettingValue("MemoryCardListView", "SortDescending",
m_ui.cardList->header()->sortIndicatorOrder() == Qt::DescendingOrder);
Host::CommitBaseSettingChanges();
}
void MemoryCardSettingsWidget::loadCardListSortState()
{
int sort_column = Host::GetBaseIntSettingValue("MemoryCardListView", "SortColumn", 0);
if (sort_column < 0 || sort_column > MemoryCardListColumn::LastModified)
sort_column = MemoryCardListColumn::Name;
const bool sort_descending = Host::GetBaseBoolSettingValue("MemoryCardListView", "SortDescending", false);
m_ui.cardList->sortByColumn(sort_column, sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder);
}
static QString getSizeSummary(const AvailableMcdInfo& mcd)
{
if (mcd.type == MemoryCardType::File)
@@ -421,12 +473,17 @@ void MemoryCardListWidget::mouseMoveEvent(QMouseEvent* event)
void MemoryCardListWidget::refresh(SettingsWindow* dialog)
{
// We don't need to sort while it's being repopulated.
setSortingEnabled(false);
clear();
// we can't use the in use flag here anyway, because the config may not be in line with per game settings.
const std::vector<AvailableMcdInfo> mcds(FileMcd_GetAvailableCards(true));
if (mcds.empty())
{
setSortingEnabled(true);
return;
}
std::array<std::string, MemoryCardSettingsWidget::MAX_SLOTS> currentCards;
for (u32 i = 0; i < static_cast<u32>(currentCards.size()); i++)
@@ -439,7 +496,7 @@ void MemoryCardListWidget::refresh(SettingsWindow* dialog)
for (const AvailableMcdInfo& mcd : mcds)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
MemoryCardListItem* item = new MemoryCardListItem();
const QDateTime mtime(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(mcd.modified_time)));
const bool inUse = (std::find(currentCards.begin(), currentCards.end(), mcd.name) != currentCards.end());
@@ -452,9 +509,13 @@ void MemoryCardListWidget::refresh(SettingsWindow* dialog)
// store formatted metadata
item->setData(0, Qt::UserRole, mcd.formatted);
item->setData(MemoryCardListColumn::LastModified, Qt::UserRole,
static_cast<qint64>(mcd.modified_time));
addTopLevelItem(item);
}
setSortingEnabled(true);
}
MemoryCardSlotWidget::MemoryCardSlotWidget(QWidget* parent)
@@ -96,6 +96,9 @@ private:
void createCard();
void saveCardListSortState();
void loadCardListSortState();
QString getSelectedCard() const;
bool isSelectedCardFormatted() const;
void updateCardActions();
+22 -29
View File
@@ -62,6 +62,7 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showUsageCPU, "EmuCore/GS", "OsdShowCPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showUsageGPU, "EmuCore/GS", "OsdShowGPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showDebugGPU, "EmuCore/GS", "OsdShowGPUDebug", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showStatsGPU, "EmuCore/GS", "OsdShowGPUStats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showStatusIndicators, "EmuCore/GS", "OsdShowIndicators", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFrameTimes, "EmuCore/GS", "OsdShowFrameTimes", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showHardwareInfo, "EmuCore/GS", "OsdShowHardwareInfo", false);
@@ -77,7 +78,7 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
#ifndef _WIN32
// Currently DX12 only
m_ui.showDebugGPU->deleteLater();
m_ui.showDebugGPU->setVisible(false);
#endif
connect(m_ui.showSettings, &QCheckBox::checkStateChanged, this, &OSDSettingsWidget::onOsdShowSettingsToggled);
@@ -127,6 +128,8 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
dialog()->registerWidgetHelp(m_ui.showDebugGPU, tr("Show GPU Debug Info"),
tr("Unchecked"), tr("Shows debug information about the renderer."));
#endif
dialog()->registerWidgetHelp(m_ui.showDebugGPU, tr("Show GPU Pipeline Statistics"),
tr("Unchecked"), tr("Shows GPU vertex shader and pixels shader invocations."));
dialog()->registerWidgetHelp(m_ui.showFrameTimes, tr("Show Frame Times"), tr("Unchecked"),
tr("Displays a graph showing the average frametimes."));
@@ -243,6 +246,7 @@ void OSDSettingsWidget::onPerformancePosChanged()
m_ui.showGSStats->setEnabled(enabled);
m_ui.showUsageCPU->setEnabled(enabled);
m_ui.showUsageGPU->setEnabled(enabled);
m_ui.showStatsGPU->setEnabled(enabled);
m_ui.showStatusIndicators->setEnabled(enabled);
m_ui.showFrameTimes->setEnabled(enabled);
m_ui.showHardwareInfo->setEnabled(enabled);
@@ -255,33 +259,7 @@ void OSDSettingsWidget::onOsdShowSettingsToggled()
m_ui.showPatches->setEnabled(enabled);
}
void OSDSettingsWidget::onSelectAllClicked()
{
const QList<QCheckBox*> checkboxes = {
m_ui.showSpeedPercentages,
m_ui.showFPS,
m_ui.showVPS,
m_ui.showResolution,
m_ui.showGSStats,
m_ui.showUsageCPU,
m_ui.showUsageGPU,
m_ui.showStatusIndicators,
m_ui.showFrameTimes,
m_ui.showHardwareInfo,
m_ui.showVersion,
m_ui.showSettings,
m_ui.showPatches,
m_ui.showInputs,
m_ui.showVideoCapture,
m_ui.showInputRec,
m_ui.showTextureReplacements,
m_ui.warnAboutUnsafeSettings};
for (QCheckBox* checkbox : checkboxes)
checkbox->setChecked(true);
}
void OSDSettingsWidget::onDeselectAllClicked()
void OSDSettingsWidget::setAllCheckboxes(bool checked)
{
const QList<QCheckBox*> checkboxes = {
m_ui.showSpeedPercentages,
@@ -291,6 +269,7 @@ void OSDSettingsWidget::onDeselectAllClicked()
m_ui.showGSStats,
m_ui.showUsageCPU,
m_ui.showUsageGPU,
m_ui.showStatsGPU,
m_ui.showFrameTimes,
m_ui.showHardwareInfo,
m_ui.showVersion,
@@ -300,7 +279,11 @@ void OSDSettingsWidget::onDeselectAllClicked()
m_ui.showTextureReplacements};
for (QCheckBox* checkbox : checkboxes)
checkbox->setChecked(false);
checkbox->setChecked(checked);
#ifdef _WIN32
m_ui.showDebugGPU->setChecked(checked);
#endif
// Keep these checked
m_ui.showStatusIndicators->setChecked(true);
@@ -309,4 +292,14 @@ void OSDSettingsWidget::onDeselectAllClicked()
m_ui.warnAboutUnsafeSettings->setChecked(true);
}
void OSDSettingsWidget::onSelectAllClicked()
{
setAllCheckboxes(true);
}
void OSDSettingsWidget::onDeselectAllClicked()
{
setAllCheckboxes(false);
}
#include "moc_OSDSettingsWidget.cpp"
+1
View File
@@ -26,6 +26,7 @@ private Q_SLOTS:
void onClearOsdFontPathClicked();
void onSelectAllClicked();
void onDeselectAllClicked();
void setAllCheckboxes(bool checked);
private:
void loadOsdFontPathSetting();
+8
View File
@@ -492,6 +492,13 @@
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QCheckBox" name="showStatsGPU">
<property name="text">
<string>Show GPU Pipeline Statistics</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@@ -530,6 +537,7 @@
<tabstop>showGSStats</tabstop>
<tabstop>showUsageCPU</tabstop>
<tabstop>showUsageGPU</tabstop>
<tabstop>showStatsGPU</tabstop>
<tabstop>showStatusIndicators</tabstop>
<tabstop>showFrameTimes</tabstop>
</tabstops>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="rgba(0,0,0,1)"><path d="M3.00488 6.99972L11.4502 1.36952C11.7861 1.14559 12.2237 1.14559 12.5596 1.36952L21.0049 6.99972V20.9997C21.0049 21.552 20.5572 21.9997 20.0049 21.9997H4.00488C3.4526 21.9997 3.00488 21.552 3.00488 20.9997V6.99972ZM5.00488 8.07009V19.9997H19.0049V8.07009L12.0049 3.40342L5.00488 8.07009ZM8.00488 15.9997H16.0049V17.9997H8.00488V15.9997ZM8.00488 12.9997H16.0049V14.9997H8.00488V12.9997ZM12.0049 10.9997C10.9003 10.9997 10.0049 10.1043 10.0049 8.99972C10.0049 7.89515 10.9003 6.99972 12.0049 6.99972C13.1095 6.99972 14.0049 7.89515 14.0049 8.99972C14.0049 10.1043 13.1095 10.9997 12.0049 10.9997Z"></path></svg>

After

Width:  |  Height:  |  Size: 699 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#fff"><path d="M3.00488 6.99972L11.4502 1.36952C11.7861 1.14559 12.2237 1.14559 12.5596 1.36952L21.0049 6.99972V20.9997C21.0049 21.552 20.5572 21.9997 20.0049 21.9997H4.00488C3.4526 21.9997 3.00488 21.552 3.00488 20.9997V6.99972ZM5.00488 8.07009V19.9997H19.0049V8.07009L12.0049 3.40342L5.00488 8.07009ZM8.00488 15.9997H16.0049V17.9997H8.00488V15.9997ZM8.00488 12.9997H16.0049V14.9997H8.00488V12.9997ZM12.0049 10.9997C10.9003 10.9997 10.0049 10.1043 10.0049 8.99972C10.0049 7.89515 10.9003 6.99972 12.0049 6.99972C13.1095 6.99972 14.0049 7.89515 14.0049 8.99972C14.0049 10.1043 13.1095 10.9997 12.0049 10.9997Z"></path></svg>

After

Width:  |  Height:  |  Size: 691 B

+2
View File
@@ -80,6 +80,7 @@
<file>icons/black/svg/play-line.svg</file>
<file>icons/black/svg/plus-line.svg</file>
<file>icons/black/svg/Popn-line.svg</file>
<file>icons/black/svg/price-tag-2-line.svg</file>
<file>icons/black/svg/price-tag-3-line.svg</file>
<file>icons/black/svg/printer-line.svg</file>
<file>icons/black/svg/realplay-sphere-line.svg</file>
@@ -193,6 +194,7 @@
<file>icons/white/svg/play-line.svg</file>
<file>icons/white/svg/plus-line.svg</file>
<file>icons/white/svg/Popn-line.svg</file>
<file>icons/white/svg/price-tag-2-line.svg</file>
<file>icons/white/svg/price-tag-3-line.svg</file>
<file>icons/white/svg/printer-line.svg</file>
<file>icons/white/svg/realplay-sphere-line.svg</file>
+1
View File
@@ -774,6 +774,7 @@ struct Pcsx2Config
OsdShowCPU : 1,
OsdShowGPU : 1,
OsdShowGPUDebug : 1,
OsdShowGPUStats : 1,
OsdShowIndicators : 1,
OsdShowFrameTimes : 1,
OsdShowHardwareInfo : 1,
+2
View File
@@ -183,6 +183,8 @@ The clamp modes are also numerically based.
* recommendedBlendingLevel [`0` or `1` or `2` or `3` or `4` or `5`] {Minimum, Basic, Medium, High, Full(Slow), Maximum (Very Slow)} Default: Automatic (No value, looks up GameDB)
* readTCOnClose [`0` or `1`] {Off, On} Default: Off (`0`) // Tab 3 Hardware Fixes (4th checkbox on right row 2)
* limit24BitDepth [`0` or `1`or `2`] {Disabled, Prioritise Upper Bits, Prioritise Lower Bits} Default: Off (`0`)
* recommendedAccurateAlphaTest [`0` or `1`] {Disabled, Advise to use AAT} Default: Off (`0`)
* recommendedHWAA1 [`0` or `1`] {Disabled, Advise to use AA1} Default: Off (`0`)
### GS Hardware Upscaling Fixes
+10
View File
@@ -229,6 +229,16 @@
"minimum": 0,
"maximum": 1
},
"recommendedAccurateAlphaTest": {
"type": "integer",
"minimum": 0,
"maximum": 1
},
"recommendedHWAA1": {
"type": "integer",
"minimum": 0,
"maximum": 1
},
"trilinearFiltering": {
"type": "integer",
"minimum": 0,
+9 -1
View File
@@ -163,6 +163,8 @@ static bool OpenGSDevice(GSRendererType renderer, bool clear_state_on_fail, bool
if (!g_gs_device->SetGPUTimingEnabled(true))
GSConfig.OsdShowGPU = false;
if (!g_gs_device->SetGPUPipelineStatisticsEnabled(true))
GSConfig.OsdShowGPUStats = false;
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", GSDevice::RenderAPIToString(new_api));
Console.WriteLn(g_gs_device->GetDriverInfo());
@@ -729,7 +731,7 @@ void GSgetStats(SmallStringBase& info)
(int)std::ceil(pm.Get(GSPerfMon::RenderPasses)),
(int)std::ceil(pm.Get(GSPerfMon::Readbacks)),
(int)std::ceil(pm.Get(GSPerfMon::TextureCopies)),
(int)std::ceil(pm.Get(GSPerfMon::DepthCopiesROV)),
(int)std::ceil(pm.Get(GSPerfMon::TextureCopiesROV)),
(int)std::ceil(pm.Get(GSPerfMon::TextureUploads)));
}
}
@@ -884,6 +886,12 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
if (!g_gs_device->SetGPUTimingEnabled(true))
GSConfig.OsdShowGPU = false;
}
if (GSConfig.OsdShowGPUStats != old_config.OsdShowGPUStats)
{
if (!g_gs_device->SetGPUPipelineStatisticsEnabled(GSConfig.OsdShowGPUStats))
GSConfig.OsdShowGPUStats = false;
}
}
void GSSetSoftwareRendering(bool software_renderer, GSInterlaceMode new_interlace)
+1 -1
View File
@@ -447,7 +447,7 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
if (!dst)
{
// allocate texture lazily
dst = g_gs_device->CreateRenderTarget(dst_size, 1, GSTexture::Format::Color, false);
dst = g_gs_device->CreateFeedbackTarget(dst_size, 1, GSTexture::Format::Color, false);
is_4bit ? (m_gpu_clut4 = dst) : (m_gpu_clut8 = dst);
m_gpu_clut_dirty = true;
}
+1 -1
View File
@@ -23,7 +23,7 @@ public:
SyncPoint,
Barriers,
RenderPasses,
DepthCopiesROV, // Overlaps with regular texture copies.
TextureCopiesROV, // Overlaps with regular texture copies.
DrawCallsROV, // Overlaps with regular draw calls.
BarriersROV, // Overlaps with regular barriers.
CounterLast,
+111 -100
View File
@@ -144,53 +144,59 @@ enum class TextureLabel
static std::array<u32, static_cast<u32>(TextureLabel::Last) + 1> s_texture_counts;
static TextureLabel GetTextureLabel(GSTexture::Type type, GSTexture::Format format)
static TextureLabel GetTextureLabel(GSTexture::Usage usage, GSTexture::Format format)
{
switch (type)
if (GSTexture::IsRenderTarget(usage))
{
case GSTexture::Type::RenderTarget:
switch (format)
{
case GSTexture::Format::Color:
return TextureLabel::ColorRT;
case GSTexture::Format::ColorHQ:
return TextureLabel::ColorHQRT;
case GSTexture::Format::ColorHDR:
return TextureLabel::ColorHDRRT;
case GSTexture::Format::ColorClip:
return TextureLabel::ColorClipRT;
case GSTexture::Format::UInt16:
return TextureLabel::U16RT;
case GSTexture::Format::UInt32:
return TextureLabel::U32RT;
case GSTexture::Format::PrimID:
return TextureLabel::PrimIDTexture;
default:
return TextureLabel::Other;
}
case GSTexture::Type::Texture:
switch (format)
{
case GSTexture::Format::Color:
return TextureLabel::Texture;
case GSTexture::Format::UNorm8:
return TextureLabel::CLUTTexture;
case GSTexture::Format::BC1:
case GSTexture::Format::BC2:
case GSTexture::Format::BC3:
case GSTexture::Format::BC7:
case GSTexture::Format::ColorHDR:
return TextureLabel::ReplacementTexture;
default:
return TextureLabel::Other;
}
case GSTexture::Type::DepthStencil:
return TextureLabel::DepthStencil;
case GSTexture::Type::RWTexture:
return TextureLabel::RWTexture;
case GSTexture::Type::Invalid:
default:
return TextureLabel::Other;
switch (format)
{
case GSTexture::Format::Color:
return TextureLabel::ColorRT;
case GSTexture::Format::ColorHQ:
return TextureLabel::ColorHQRT;
case GSTexture::Format::ColorHDR:
return TextureLabel::ColorHDRRT;
case GSTexture::Format::ColorClip:
return TextureLabel::ColorClipRT;
case GSTexture::Format::UInt16:
return TextureLabel::U16RT;
case GSTexture::Format::UInt32:
return TextureLabel::U32RT;
case GSTexture::Format::PrimID:
return TextureLabel::PrimIDTexture;
default:
return TextureLabel::Other;
}
}
else if (GSTexture::IsTexture(usage))
{
switch (format)
{
case GSTexture::Format::Color:
return TextureLabel::Texture;
case GSTexture::Format::UNorm8:
return TextureLabel::CLUTTexture;
case GSTexture::Format::BC1:
case GSTexture::Format::BC2:
case GSTexture::Format::BC3:
case GSTexture::Format::BC7:
case GSTexture::Format::ColorHDR:
return TextureLabel::ReplacementTexture;
default:
return TextureLabel::Other;
}
}
else if (GSTexture::IsDepthStencil(usage))
{
return TextureLabel::DepthStencil;
}
else if (GSTexture::IsShaderWrite(usage))
{
return TextureLabel::RWTexture;
}
else
{
return TextureLabel::Other;
}
}
@@ -594,11 +600,16 @@ void GSDevice::TextureRecycleDeleter::operator()(GSTexture* const tex)
g_gs_device->Recycle(tex);
}
GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
GSTexture* GSDevice::FetchSurface(GSTexture::Usage usage, const GSVector2i& size, int levels, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(usage, size.x, size.y, levels, format, clear, prefer_reuse);
}
GSTexture* GSDevice::FetchSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse)
{
const GSVector2i size(std::clamp(width, 1, static_cast<int>(g_gs_device->GetMaxTextureSize())),
std::clamp(height, 1, static_cast<int>(g_gs_device->GetMaxTextureSize())));
FastList<GSTexture*>& pool = m_pool[type != GSTexture::Type::Texture];
FastList<GSTexture*>& pool = m_pool[!GSTexture::IsTexture(usage)];
GSTexture* t = nullptr;
auto fallback = pool.end();
@@ -609,9 +620,9 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
pxAssert(t);
if (t->GetType() == type && t->GetFormat() == format && t->GetSize() == size && t->GetMipmapLevels() == levels)
if (t->GetUsage() == usage && t->GetFormat() == format && t->GetSize() == size && t->GetMipmapLevels() == levels)
{
if (!prefer_unused_texture || t->GetLastFrameUsed() != m_frame)
if (prefer_reuse || t->GetLastFrameUsed() != m_frame)
{
m_pool_memory_usage -= t->GetMemUsage();
pool.erase(i);
@@ -628,7 +639,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
if (!t)
{
if (pool.size() >= ((type == GSTexture::Type::Texture) ? MAX_POOLED_TEXTURES : MAX_POOLED_TARGETS) &&
if (pool.size() >= (GSTexture::IsTexture(usage) ? MAX_POOLED_TEXTURES : MAX_POOLED_TARGETS) &&
fallback != pool.end())
{
t = *fallback;
@@ -637,12 +648,12 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
}
else
{
t = CreateSurface(type, size.x, size.y, levels, format);
t = CreateSurface(usage, size.x, size.y, levels, format);
if (!t)
{
ERROR_LOG("GS: Memory allocation failure for {}x{} texture. Purging pool and retrying.", size.x, size.y);
PurgePool();
t = CreateSurface(type, size.x, size.y, levels, format);
t = CreateSurface(usage, size.x, size.y, levels, format);
if (!t)
{
ERROR_LOG("GS: Memory allocation failure for {}x{} texture after purging pool.", size.x, size.y);
@@ -653,7 +664,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
#ifdef PCSX2_DEVBUILD
if (GSConfig.UseDebugDevice)
{
const TextureLabel label = GetTextureLabel(type, format);
const TextureLabel label = GetTextureLabel(usage, format);
const u32 id = ++s_texture_counts[static_cast<u32>(label)];
t->SetDebugName(TinyString::from_format("{} {}", TextureLabelString(label), id));
}
@@ -661,26 +672,19 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
}
}
switch (type)
if (t->IsRenderTarget())
{
case GSTexture::Type::RenderTarget:
{
if (clear)
ClearRenderTarget(t, 0);
else
InvalidateRenderTarget(t);
}
break;
case GSTexture::Type::DepthStencil:
{
if (clear)
ClearDepth(t, 0.0f);
else
InvalidateRenderTarget(t);
}
break;
default:
break;
if (clear)
ClearRenderTarget(t, 0);
else
InvalidateRenderTarget(t);
}
else if (t->IsDepthStencil())
{
if (clear)
ClearDepth(t, 0.0f);
else
InvalidateRenderTarget(t);
}
return t;
@@ -692,8 +696,6 @@ void GSDevice::Recycle(GSTexture* t)
return;
t->SetLastFrameUsed(m_frame);
t->ClearUnorderedAccess();
#ifdef PCSX2_DEVBUILD
t->SetDebugName("");
@@ -762,46 +764,52 @@ void GSDevice::PurgePool()
GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, !prefer_reuse);
return FetchSurface(GSTexture::RenderTarget, w, h, 1, format, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, format, clear, !prefer_reuse);
return FetchSurface(GSTexture::RenderTarget, size.x, size.y, 1, format, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateFeedbackTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::FeedbackTarget, w, h, 1, format, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateFeedbackTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::FeedbackTarget, size.x, size.y, 1, format, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateShaderWriteTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::ShaderWriteTarget, w, h, 1, format, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateShaderWriteTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::ShaderWriteTarget, size.x, size.y, 1, format, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateDepthStencil(int w, int h, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil,
clear, !prefer_reuse);
return FetchSurface(GSTexture::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateDepthStencil(const GSVector2i& size, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil,
clear, !prefer_reuse);
return FetchSurface(GSTexture::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateDepthColor(int w, int h, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, GSTexture::Format::DepthColor,
clear, !prefer_reuse);
}
GSTexture* GSDevice::CreateDepthColor(const GSVector2i& size, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, GSTexture::Format::DepthColor,
clear, !prefer_reuse);
}
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse)
{
pxAssert(mipmap_levels != 0 && (mipmap_levels < 0 || mipmap_levels <= GetMipmapLevelsForSize(w, h)));
const int levels = mipmap_levels < 0 ? GetMipmapLevelsForSize(w, h) : mipmap_levels;
return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, m_features.prefer_new_textures && !prefer_reuse);
return FetchSurface(GSTexture::Texture, w, h, levels, format, false, m_features.prefer_new_textures && prefer_reuse);
}
GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse)
{
return CreateTexture(size.x, size.y, mipmap_levels, format, prefer_reuse);
}
@@ -818,7 +826,7 @@ GSTexture* GSDevice::CreateCompatible(GSTexture* tex, const GSVector2i& size, bo
GSTexture* GSDevice::CreateCompatible(GSTexture* tex, int w, int h, bool clear, bool prefer_reuse)
{
return FetchSurface(tex->GetType(), w, h, 1, tex->GetFormat(), clear, !prefer_reuse);
return FetchSurface(tex->GetUsage(), w, h, 1, tex->GetFormat(), clear, prefer_reuse);
}
void GSDevice::DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex,
@@ -1070,8 +1078,9 @@ bool GSDevice::ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_con
}
const GSTexture::Format fmt = orig_tex ? orig_tex->GetFormat() : GSTexture::Format::Color;
const GSTexture::Usage usage = orig_tex ? orig_tex->GetUsage() : GSTexture::RenderTarget;
const bool really_preserve_contents = (preserve_contents && orig_tex);
GSTexture* new_tex = FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, fmt, !really_preserve_contents, true);
GSTexture* new_tex = FetchSurface(usage, w, h, 1, fmt, !really_preserve_contents, false);
if (!new_tex)
{
Console.WriteLn("%dx%d texture allocation failed in ResizeTexture()", w, h);
@@ -1102,7 +1111,7 @@ void GSDevice::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea)
// Create a temporary RT and copy the area needed for the draw.
const int w = ds->GetWidth();
const int h = ds->GetHeight();
m_ds_as_rt = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::DepthColor, false, true);
m_ds_as_rt = g_gs_device->CreateFeedbackTarget(w, h, GSTexture::Format::DepthColor, false, true);
const GSVector4 dRect(drawarea);
const GSVector4 sRect(dRect.x / w, dRect.y / h, dRect.z / w, dRect.w / h);
StretchRectAuto(ds, sRect, m_ds_as_rt, dRect, Nearest);
@@ -1158,7 +1167,7 @@ void GSDevice::CAS(GSTexture*& tex, GSVector4i& src_rect, GSVector4& src_uv, con
if (!m_cas || m_cas->GetWidth() != dst_width || m_cas->GetHeight() != dst_height)
{
delete m_cas;
m_cas = CreateSurface(GSTexture::Type::RWTexture, dst_width, dst_height, 1, GSTexture::Format::Color);
m_cas = CreateSurface(GSTexture::ShaderWriteTexture, dst_width, dst_height, 1, GSTexture::Format::Color);
if (!m_cas)
{
Console.Error("Failed to allocate CAS RW texture.");
@@ -1705,6 +1714,7 @@ static void DumpPSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::PS
DumpVector4(out, "DitherMatrix_2", cb.DitherMatrix[2]);
DumpVector4(out, "DitherMatrix_3", cb.DitherMatrix[3]);
DumpVector4(out, "ScaleFactor", cb.ScaleFactor);
out.WriteLn("LineCovScale: {}", cb.LineCovScale);
}
static void DumpVSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::VSConstantBuffer& cb)
@@ -1714,7 +1724,8 @@ static void DumpVSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::VS
DumpVector2(out, "texture_scale", cb.texture_scale);
DumpVector2(out, "texture_offset", cb.texture_offset);
DumpVector2(out, "point_size", cb.point_size);
DumpVector2(out, "max_depth", cb.max_depth);
out.WriteLn("max_depth: {}", cb.max_depth);
out.WriteLn("line_aa1_width: {}", cb.line_aa1_width);
}
static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf,
+28 -8
View File
@@ -29,6 +29,12 @@ static inline constexpr Filter BilnIf(bool biln)
return biln ? Biln : Nearest;
}
struct GPUPipelineStatistics
{
u64 vs_invocations;
u64 ps_invocations;
};
enum class ShaderConvert
{
COPY = 0,
@@ -1027,7 +1033,8 @@ struct alignas(16) GSHWDrawConfig
GSVector2 texture_scale;
GSVector2 texture_offset;
GSVector2 point_size;
GSVector2i max_depth;
u32 max_depth;
float line_aa1_width;
__fi VSConstantBuffer()
{
memset(static_cast<void*>(this), 0, sizeof(*this));
@@ -1117,6 +1124,10 @@ struct alignas(16) GSHWDrawConfig
GSVector4 DitherMatrix[4];
GSVector4 ScaleFactor;
float LineCovScale;
float _pad0;
float _pad1;
float _pad2;
__fi PSConstantBuffer()
{
@@ -1477,8 +1488,7 @@ protected:
bool AcquireWindow(bool recreate_window);
virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0;
GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture);
virtual GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) = 0;
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) = 0;
virtual void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) = 0;
@@ -1488,7 +1498,7 @@ protected:
/// Resolves CAS shader includes for the specified source.
static bool GetCASShaderSource(std::string* source);
/// Applies CAS and writes to the destination texture, which should be a RWTexture.
/// Applies CAS and writes to the destination texture, which should be a shader writeable texture.
virtual bool DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array<u32, NUM_CAS_CONSTANTS>& constants) = 0;
/// Perform texture operations for ImGui
@@ -1606,6 +1616,12 @@ public:
/// Returns the amount of GPU time utilized since the last time this method was called.
virtual float GetAndResetAccumulatedGPUTime() = 0;
/// Enables/disables GPU pipeline statistics.
virtual bool SetGPUPipelineStatisticsEnabled(bool enabled) = 0;
/// Get the pipeline statistics for the last frame.
virtual GPUPipelineStatistics GetAndResetAccumulatedGPUPipelineStatistics() = 0;
/// Returns true if not enough time has passed for present to not block.
bool ShouldSkipPresentingFrame();
@@ -1621,13 +1637,17 @@ public:
virtual void PopDebugGroup() = 0;
virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) = 0;
GSTexture* FetchSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
GSTexture* FetchSurface(GSTexture::Usage usage, const GSVector2i& size, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateDepthStencil(int w, int h, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateDepthColor(int w, int h, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
GSTexture* CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateFeedbackTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateFeedbackTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateShaderWriteTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateShaderWriteTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateDepthStencil(int w, int h, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateDepthStencil(const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateDepthColor(const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
GSTexture* CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
GSTexture* CreateCompatible(GSTexture* tex, bool clear = true, bool prefer_reuse = true);
GSTexture* CreateCompatible(GSTexture* tex, const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
+3 -1
View File
@@ -700,7 +700,9 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
EndPresentFrame();
PerformanceMetrics::OnGPUPresent(g_gs_device->GetAndResetAccumulatedGPUTime());
const float gpu_time = g_gs_device->GetAndResetAccumulatedGPUTime();
GPUPipelineStatistics gpu_stats = g_gs_device->GetAndResetAccumulatedGPUPipelineStatistics();
PerformanceMetrics::OnGPUPresent(gpu_time, gpu_stats.vs_invocations, gpu_stats.ps_invocations);
}
PerformanceMetrics::Update(registers_written, fb_sprite_frame, false);
+35
View File
@@ -16,6 +16,30 @@ GSTexture::GSTexture() = default;
GSTexture::~GSTexture() = default;
bool GSTexture::ValidateUsageAndFormat(Usage usage, Format format)
{
if (IsDepthStencil(usage) && (usage & (Usage::ShaderWrite | Usage::RenderTarget)))
return false; // DS is not compatible with Write or RT
if (IsFeedback(usage) && !(usage & (Usage::DepthStencil | Usage::RenderTarget)))
return false; // Feedback requires RT or DS
if (usage == (Usage::ShaderWrite | Usage::RenderTarget))
return false; // We always include Feedback for RT+Write
if (format == Format::UNorm8 && !IsTexture(usage)) // Unorm8 only used for sampling
return false;
if (IsFeedback(usage) && !IsFeedbackFormat(format)) // Only some formats used with feedback
return false;
if (IsShaderWrite(usage) && !IsShaderWriteFormat(format)) // Only some formats used with shader write
return false;
if (IsDepthStencil(usage) && (format != Format::DepthStencil)) // Only use DepthStencil format with DepthStencil usage
return false;
if (!g_gs_device->Features().depth_feedback)
{
if (IsDepthStencil(usage) && IsFeedback(usage))
return false;
}
return true;
}
bool GSTexture::Save(const std::string& fn)
{
// Depth textures need special treatment - we have a stencil component.
@@ -174,6 +198,17 @@ u32 GSTexture::CalcUploadSize(Format format, u32 height, u32 pitch)
return pitch * ((static_cast<u32>(height) + (block_size - 1)) / block_size);
}
bool GSTexture::IsFeedbackFormat(Format format)
{
return format == Format::Color || format == Format::ColorClip ||
format == Format::DepthColor || format == Format::DepthStencil;
}
bool GSTexture::IsShaderWriteFormat(Format format)
{
return format == Format::Color || format == Format::DepthColor;
}
void GSTexture::GenerateMipmapsIfNeeded()
{
if (!m_needs_mipmaps_generated || m_mipmap_levels <= 1 || IsCompressedFormat())
+96 -27
View File
@@ -3,11 +3,23 @@
#pragma once
#include "common/EnumOps.h"
#include "GS/GSVector.h"
#include <string>
#include <string_view>
enum class TextureUsage : u8
{
Texture = 0,
DepthStencil = 1,
RenderTarget = 2,
Feedback = 4,
ShaderWrite = 8,
};
MARK_ENUM_AS_FLAGS(TextureUsage);
class GSTexture
{
public:
@@ -17,14 +29,21 @@ public:
int pitch;
};
enum class Type : u8
{
Invalid = 0,
RenderTarget = 1,
DepthStencil,
Texture, // Generic texture (usually is color textures loaded by the game)
RWTexture, // UAV
};
using Usage = TextureUsage;
// Flags that shouldn't be used alone
static constexpr Usage ShaderWrite = Usage::ShaderWrite;
static constexpr Usage Feedback = Usage::Feedback;
static constexpr Usage FeedbackOrShaderWrite = Usage::Feedback | Usage::ShaderWrite;
// All valid combinations
static constexpr Usage Texture = Usage::Texture;
static constexpr Usage RenderTarget = Usage::RenderTarget;
static constexpr Usage DepthStencil = Usage::DepthStencil;
static constexpr Usage FeedbackTarget = Usage::RenderTarget | Usage::Feedback;
static constexpr Usage FeedbackDepth = Usage::DepthStencil | Usage::Feedback;
static constexpr Usage ShaderWriteTarget = Usage::RenderTarget | Usage::Feedback | Usage::ShaderWrite;
static constexpr Usage ShaderWriteTexture = Usage::Texture | Usage::ShaderWrite;
enum class Format : u8
{
@@ -34,7 +53,7 @@ public:
ColorHDR, ///< High dynamic range (RGBA16F) color texture
ColorClip, ///< Color texture with more bits for colclip (wrap) emulation, given that blending requires 9bpc (RGBA16Unorm)
DepthStencil, ///< Depth stencil texture
DepthColor, ///< For treating depth texture as RT
DepthColor, ///< For treating depth texture as RT
UNorm8, ///< A8UNorm texture for paletted textures and the OSD font
UInt16, ///< UInt16 texture for reading back 16-bit depth
UInt32, ///< UInt32 texture for reading back 24 and 32-bit depth
@@ -46,6 +65,8 @@ public:
Last = BC7,
};
static bool ValidateUsageAndFormat(Usage usage, Format format);
enum class State : u8
{
Dirty,
@@ -62,7 +83,7 @@ public:
protected:
GSVector2i m_size{};
int m_mipmap_levels = 0;
Type m_type = Type::Invalid;
Usage m_usage = Usage::Texture;
Format m_format = Format::Invalid;
State m_state = State::Dirty;
@@ -73,10 +94,6 @@ protected:
bool m_needs_mipmaps_generated = true;
ClearValue m_clear_value = {};
// For GL/DX11 since they don't track layouts.
// Used heuristically to decide whether to use ROV for a draw.
bool m_unordered_access = false;
#ifdef PCSX2_DEVBUILD
std::string m_debug_name;
#endif
@@ -107,7 +124,7 @@ public:
__fi int GetMipmapLevels() const { return m_mipmap_levels; }
__fi bool IsMipmap() const { return m_mipmap_levels > 1; }
__fi Type GetType() const { return m_type; }
__fi Usage GetUsage() const { return m_usage; }
__fi Format GetFormat() const { return m_format; }
__fi bool IsCompressedFormat() const { return IsCompressedFormat(m_format); }
@@ -118,6 +135,8 @@ public:
static u32 CalcUploadPitch(Format format, u32 width);
static u32 CalcUploadRowLengthFromPitch(Format format, u32 pitch);
static u32 CalcUploadSize(Format format, u32 height, u32 pitch);
static bool IsFeedbackFormat(Format format);
static bool IsShaderWriteFormat(Format format);
u32 GetCompressedBytesPerBlock() const;
u32 GetCompressedBlockSize() const;
@@ -125,29 +144,85 @@ public:
u32 CalcUploadRowLengthFromPitch(u32 pitch) const;
u32 CalcUploadSize(u32 height, u32 pitch) const;
static __fi bool IsRenderTarget(Usage usage)
{
return (usage & RenderTarget);
}
static __fi bool IsDepthStencil(Usage usage)
{
return (usage & DepthStencil);
}
static __fi bool IsRenderTargetOrDepthStencil(Usage usage)
{
return IsRenderTarget(usage) || IsDepthStencil(usage);
}
static __fi bool IsDepthColor(Usage usage, Format format)
{
return IsRenderTarget(usage) && (format == Format::DepthColor);
}
static __fi bool IsTexture(Usage usage)
{
return usage == Texture;
}
static __fi bool IsDepthLike(Usage usage, Format format)
{
return IsDepthStencil(usage) || IsDepthColor(usage, format);
}
static __fi bool IsFeedback(Usage usage)
{
return (usage & Feedback);
}
static __fi bool IsShaderWrite(Usage usage)
{
return (usage & ShaderWrite);
}
static __fi bool IsFeedbackOrShaderWrite(Usage usage)
{
return IsFeedback(usage) || IsShaderWrite(usage);
}
__fi bool IsRenderTargetOrDepthStencil() const
{
return (m_type >= Type::RenderTarget && m_type <= Type::DepthStencil);
return IsRenderTargetOrDepthStencil(m_usage);
}
__fi bool IsRenderTarget() const
{
return (m_type == Type::RenderTarget);
return IsRenderTarget(m_usage);
}
__fi bool IsDepthStencil() const
{
return (m_type == Type::DepthStencil);
return IsDepthStencil(m_usage);
}
__fi bool IsDepthColor() const
{
return (m_type == Type::RenderTarget && m_format == Format::DepthColor);
return IsDepthColor(m_usage, m_format);
}
__fi bool IsTexture() const
{
return (m_type == Type::Texture);
return IsTexture(m_usage);
}
__fi bool IsDepthLike() const
{
return IsDepthStencil() || IsDepthColor();
return IsDepthLike(m_usage, m_format);
}
__fi bool IsFeedback() const
{
return IsFeedback(m_usage);
}
__fi bool IsShaderWrite() const
{
return IsShaderWrite(m_usage);
}
__fi bool IsFeedbackOrShaderWrite() const
{
return IsFeedbackOrShaderWrite(m_usage);
}
virtual bool IsShaderWriteMode() const
{
// Backends that track state explicitly can specialize this to use the actual state.
return IsShaderWrite();
}
__fi State GetState() const { return m_state; }
@@ -181,12 +256,6 @@ public:
// Typical size of a RGBA texture
u32 GetMemUsage() const { return m_size.x * m_size.y * (m_format == Format::UNorm8 ? 1 : 4); }
// The unordered access flag is sticky, so once it's set we keep using ROV for the target
// until it's recycled/destroyed. Only used for DX11/GL, which don't track actual resource layout/state.
virtual bool IsUnorderedAccess() const { return m_unordered_access; }
void SetUnorderedAccess() { m_unordered_access = true; }
void ClearUnorderedAccess() { m_unordered_access = false; }
// Helper routines for formats/types
static bool IsCompressedFormat(Format format) { return (format >= Format::BC1 && format <= Format::BC7); }
};
+190 -46
View File
@@ -48,6 +48,15 @@ static bool IsTextureFormatHWBlendable(ID3D11Device* dev, DXGI_FORMAT format)
return (support & D3D11_FORMAT_SUPPORT_RENDER_TARGET) && (support & D3D11_FORMAT_SUPPORT_BLENDABLE);
}
static bool IsTextureFormatUAVCapable(ID3D11Device* dev, DXGI_FORMAT format)
{
UINT support;
if (FAILED(dev->CheckFormatSupport(format, &support)))
return false;
return (support & D3D11_FORMAT_SUPPORT_TYPED_UNORDERED_ACCESS_VIEW) != 0;
}
GSDevice11::GSDevice11()
{
memset(&m_state, 0, sizeof(m_state));
@@ -594,7 +603,8 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
}
// 1x1 dummy texture.
m_null_texture = CreateSurface(GSTexture::Type::RenderTarget, 1, 1, 1, GSTexture::Format::Color);
const GSTexture::Usage null_usage = m_features.rov ? GSTexture::ShaderWriteTarget : GSTexture::Feedback;
m_null_texture = CreateSurface(null_usage, 1, 1, 1, GSTexture::Format::Color);
if (!m_null_texture)
return false;
@@ -608,6 +618,7 @@ void GSDevice11::Destroy()
GSDevice::Destroy();
DestroySwapChain();
DestroyTimestampQueries();
DestroyPipelineStatisticsQueries();
m_convert = {};
m_present = {};
@@ -642,6 +653,13 @@ void GSDevice11::Destroy()
}
m_state.current_rt = nullptr;
if (m_state.dsv_as_rtv)
{
m_state.dsv_as_rtv->Release();
m_state.dsv_as_rtv = nullptr;
}
m_state.current_ds_as_rt = nullptr;
if (m_state.dsv)
{
m_state.dsv->Release();
@@ -695,7 +713,7 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
m_features.bptc_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC7_UNORM);
m_features.cas_sharpening = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.test_and_sample_depth = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.depth_feedback = m_features.feedback_loops();
m_features.depth_feedback = m_features.multidraw_fb_copy && GSConfig.DepthFeedbackMode == GSDepthFeedbackMode::Depth;
m_features.aa1 = GSConfig.HWAA1 && m_features.vs_expand && m_features.feedback_loops();
m_max_texture_size = (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ?
@@ -710,6 +728,11 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
D3D11_FEATURE_DATA_D3D11_OPTIONS2 options2{};
m_dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS2, &options2, sizeof(options2));
m_features.rov = m_uav_texture && options2.ROVsSupported;
for (u32 fmt = static_cast<u32>(GSTexture::Format::Color); fmt <= static_cast<u32>(GSTexture::Format::PrimID); fmt++)
{
if (GSTexture::IsShaderWriteFormat(static_cast<GSTexture::Format>(fmt)))
m_features.rov &= IsTextureFormatUAVCapable(m_dev.get(), GSTexture11::GetDXGIFormat(static_cast<GSTexture::Format>(fmt)));
}
// Let the user know if said features are available.
Console.WriteLnFmt("D3D11: DXTn Texture Compression: {}", m_features.dxt_textures ? "Supported" : "Not Supported");
@@ -717,6 +740,7 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
Console.WriteLnFmt("D3D11: Conservative Depth: {}", m_conservative_depth ? "Supported" : "Not Supported");
Console.WriteLnFmt("D3D11: Depth Testing and Sampling: {}", m_features.test_and_sample_depth ? "Supported" : "Not Supported");
Console.WriteLnFmt("D3D11: RGBA16 UNORM Hardware Blending: {}", m_rgba16_unorm_hw_blend ? "Supported" : "Not Supported");
Console.WriteLnFmt("D3D11: Rasterizer Ordered Views: {}", m_features.rov ? "Supported" : "Not Supported");
}
bool GSDevice11::HasSurface() const
@@ -1059,6 +1083,10 @@ GSDevice::PresentResult GSDevice11::BeginPresent(bool frame_skip)
if (m_vsync_mode == GSVSyncMode::FIFO && m_gpu_timing_enabled)
PopTimestampQuery();
// Get the pipeline statistics for this frame before postprocessing.
if (m_gpu_pipeline_statistics_enabled)
PopPipelineStatisticsQuery();
m_ctx->ClearRenderTargetView(m_swap_chain_rtv.get(), s_present_clear_color.data());
m_ctx->OMSetRenderTargets(1, m_swap_chain_rtv.addressof(), nullptr);
if (m_state.rtv)
@@ -1090,8 +1118,11 @@ void GSDevice11::EndPresent()
if (m_vsync_mode != GSVSyncMode::FIFO && m_gpu_timing_enabled)
PopTimestampQuery();
if (m_gpu_pipeline_statistics_enabled)
PopPipelineStatisticsQuery();
// clear out the swap chain view, it might get resized..
OMSetRenderTargets(nullptr, nullptr);
OMSetRenderTargets(nullptr, nullptr, nullptr);
const UINT sync_interval = static_cast<UINT>(m_vsync_mode == GSVSyncMode::FIFO);
const UINT flags = (m_vsync_mode == GSVSyncMode::Disabled && m_using_allow_tearing) ? DXGI_PRESENT_ALLOW_TEARING : 0;
@@ -1099,6 +1130,9 @@ void GSDevice11::EndPresent()
if (m_gpu_timing_enabled)
KickTimestampQuery();
if (m_gpu_pipeline_statistics_enabled)
KickPipelineStatisticsQuery();
}
bool GSDevice11::CreateTimestampQueries()
@@ -1219,6 +1253,95 @@ float GSDevice11::GetAndResetAccumulatedGPUTime()
return value;
}
bool GSDevice11::CreatePipelineStatisticsQueries()
{
for (u32 i = 0; i < NUM_PIPELINE_STATISTICS_QUERIES; i++)
{
const CD3D11_QUERY_DESC qdesc(D3D11_QUERY_PIPELINE_STATISTICS);
const HRESULT hr = m_dev->CreateQuery(&qdesc, m_pipeline_statistics_queries[i].put());
if (FAILED(hr))
{
m_pipeline_statistics_queries = {};
return false;
}
}
KickPipelineStatisticsQuery();
return true;
}
void GSDevice11::KickPipelineStatisticsQuery()
{
if (m_pipeline_statistics_query_started || !m_pipeline_statistics_queries[0] ||
m_waiting_pipeline_statistics_queries == NUM_PIPELINE_STATISTICS_QUERIES)
return;
m_ctx->Begin(m_pipeline_statistics_queries[m_write_pipeline_statistics_query].get());
m_pipeline_statistics_query_started = true;
}
void GSDevice11::DestroyPipelineStatisticsQueries()
{
if (!m_pipeline_statistics_queries[0])
return;
if (m_pipeline_statistics_query_started)
m_ctx->End(m_pipeline_statistics_queries[m_write_timestamp_query].get());
m_timestamp_queries = {};
m_read_timestamp_query = 0;
m_write_timestamp_query = 0;
m_waiting_timestamp_queries = 0;
m_timestamp_query_started = 0;
}
void GSDevice11::PopPipelineStatisticsQuery()
{
while (m_waiting_pipeline_statistics_queries > 0)
{
D3D11_QUERY_DATA_PIPELINE_STATISTICS stats{};
const HRESULT stats_hr = m_ctx->GetData(
m_pipeline_statistics_queries[m_read_pipeline_statistics_query].get(), &stats, sizeof(stats), 0);
if (stats_hr != S_OK)
break;
m_accumulated_gpu_pipeline_statistics.vs_invocations += stats.VSInvocations;
m_accumulated_gpu_pipeline_statistics.ps_invocations += stats.PSInvocations;
m_read_pipeline_statistics_query = (m_read_pipeline_statistics_query + 1) % NUM_PIPELINE_STATISTICS_QUERIES;
m_waiting_pipeline_statistics_queries--;
}
if (m_pipeline_statistics_query_started)
{
m_ctx->End(m_pipeline_statistics_queries[m_write_pipeline_statistics_query].get());
m_write_pipeline_statistics_query = (m_write_pipeline_statistics_query + 1) % NUM_PIPELINE_STATISTICS_QUERIES;
m_pipeline_statistics_query_started = false;
m_waiting_pipeline_statistics_queries++;
}
}
GPUPipelineStatistics GSDevice11::GetAndResetAccumulatedGPUPipelineStatistics()
{
GPUPipelineStatistics stats = m_accumulated_gpu_pipeline_statistics;
m_accumulated_gpu_pipeline_statistics = {};
return stats;
}
bool GSDevice11::SetGPUPipelineStatisticsEnabled(bool enabled)
{
m_gpu_pipeline_statistics_enabled = enabled;
if (m_gpu_pipeline_statistics_enabled)
{
return CreatePipelineStatisticsQueries();
}
else
{
DestroyPipelineStatisticsQueries();
return true;
}
}
void GSDevice11::DrawPrimitive()
{
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
@@ -1334,8 +1457,10 @@ void GSDevice11::InsertDebugMessage(DebugMessageCategory category, const char* f
m_annotation->SetMarker(StringUtil::UTF8StringToWideString(str).c_str());
}
GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
GSTexture* GSDevice11::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
{
pxAssert(GSTexture::ValidateUsageAndFormat(usage, format));
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = width;
desc.Height = height;
@@ -1346,26 +1471,27 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
switch (type)
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
if (GSTexture::IsTexture(usage))
{
case GSTexture::Type::RenderTarget:
desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
if (m_uav_texture)
desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
break;
case GSTexture::Type::DepthStencil:
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
break;
case GSTexture::Type::Texture:
desc.BindFlags = (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) : D3D11_BIND_SHADER_RESOURCE;
desc.MiscFlags = (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
break;
case GSTexture::Type::RWTexture:
pxAssert(m_uav_texture);
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
break;
default:
break;
desc.BindFlags |= (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_BIND_RENDER_TARGET : 0;
desc.MiscFlags |= (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
}
if (GSTexture::IsRenderTarget(usage))
{
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
}
if (GSTexture::IsDepthStencil(usage))
{
desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
}
if (GSTexture::IsShaderWrite(usage))
{
desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
}
wil::com_ptr_nothrow<ID3D11Texture2D> texture;
@@ -1376,7 +1502,7 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height
return nullptr;
}
return new GSTexture11(std::move(texture), desc, type, format);
return new GSTexture11(std::move(texture), desc, usage, format);
}
std::unique_ptr<GSDownloadTexture> GSDevice11::CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format)
@@ -1466,9 +1592,9 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
{
ds = dTex->GetSize();
if (draw_in_depth)
OMSetRenderTargets(nullptr, dTex);
OMSetRenderTargets(nullptr, nullptr, dTex);
else
OMSetRenderTargets(dTex, nullptr);
OMSetRenderTargets(dTex, nullptr, nullptr);
}
else
{
@@ -1532,7 +1658,7 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
if (dTex)
{
ds = dTex->GetSize();
OMSetRenderTargets(dTex, nullptr);
OMSetRenderTargets(dTex, nullptr, nullptr);
}
else
{
@@ -1655,7 +1781,7 @@ void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_re
PSSetShader(GetConvertShader(shader), nullptr);
OMSetDepthStencilState(dTex->IsRenderTarget() ? m_convert.dss.get() : m_convert.dss_write.get(), 0);
OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, dTex->IsDepthStencil() ? dTex : nullptr);
OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, nullptr, dTex->IsDepthStencil() ? dTex : nullptr);
const GSVector2 ds(static_cast<float>(dTex->GetWidth()), static_cast<float>(dTex->GetHeight()));
GSTexture* last_tex = rects[0].src;
@@ -1891,6 +2017,7 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
sm.AddMacro("PIXEL_SHADER", 1);
sm.AddMacro("PS_HAS_CONSERVATIVE_DEPTH", m_conservative_depth);
sm.AddMacro("PS_DEPTH_FEEDBACK_SUPPORT", m_features.depth_feedback ? 1 : 2);
sm.AddMacro("PS_FST", sel.fst);
sm.AddMacro("PS_WMS", sel.wms);
sm.AddMacro("PS_WMT", sel.wmt);
@@ -2153,7 +2280,7 @@ bool GSDevice11::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons
ID3D11ShaderResourceView* srvs[1] = {*static_cast<GSTexture11*>(sTex)};
ID3D11UnorderedAccessView* uavs[1] = {*static_cast<GSTexture11*>(dTex)};
OMSetRenderTargets(nullptr, nullptr);
OMSetRenderTargets(nullptr, nullptr, nullptr);
m_ctx->UpdateSubresource(m_cas.cb.get(), 0, nullptr, constants.data(), 0, 0);
m_ctx->CSSetConstantBuffers(0, 1, m_cas.cb.addressof());
m_ctx->CSSetShader(sharpen_only ? m_cas.cs_sharpen.get() : m_cas.cs_upscale.get(), nullptr, 0);
@@ -2347,7 +2474,7 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV
OMSetDepthStencilState(m_date.dss.get(), 1);
OMSetBlendState(m_date.bs.get(), 0);
OMSetRenderTargets(nullptr, ds);
OMSetRenderTargets(nullptr, nullptr, ds);
// ia
@@ -2740,13 +2867,14 @@ void GSDevice11::OMSetBlendState(ID3D11BlendState* bs, u8 bf)
}
}
void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_uav_tex, GSTexture* ds_uav_tex,
void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds_as_rt, GSTexture* ds, GSTexture* rt_uav_tex, GSTexture* ds_uav_tex,
const GSVector4i* scissor, ID3D11DepthStencilView* read_only_dsv)
{
if (!(rt || rt_uav_tex) && ds_uav_tex)
rt_uav_tex = m_null_texture; // Fill in the first UAV slot with the null texture.
ID3D11RenderTargetView* rtv = nullptr;
ID3D11RenderTargetView* dsv_as_rtv = nullptr;
ID3D11DepthStencilView* dsv = nullptr;
ID3D11UnorderedAccessView* rt_uav = nullptr;
ID3D11UnorderedAccessView* ds_uav = nullptr;
@@ -2756,6 +2884,11 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
CommitClear(rt);
rtv = *static_cast<GSTexture11*>(rt);
}
if (ds_as_rt)
{
CommitClear(ds_as_rt);
dsv_as_rtv = *static_cast<GSTexture11*>(ds_as_rt);
}
if (ds)
{
CommitClear(ds);
@@ -2772,7 +2905,7 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
ds_uav = *static_cast<GSTexture11*>(ds_uav_tex);
}
const bool changed = (m_state.rtv != rtv || m_state.dsv != dsv || m_state.rt_uav != rt_uav || m_state.ds_uav != ds_uav);
const bool changed = (m_state.rtv != rtv || m_state.dsv_as_rtv != dsv_as_rtv || m_state.dsv != dsv || m_state.rt_uav != rt_uav || m_state.ds_uav != ds_uav);
const bool no_uavs = m_state.rt_uav == nullptr && rt_uav == nullptr && m_state.ds_uav == nullptr && ds_uav == nullptr;
if (changed)
@@ -2787,6 +2920,15 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
m_state.rtv = rtv;
m_state.current_rt = rt;
}
if (m_state.dsv_as_rtv != dsv_as_rtv)
{
if (m_state.dsv_as_rtv)
m_state.dsv_as_rtv->Release();
if (dsv_as_rtv)
dsv_as_rtv->AddRef();
m_state.rtv = dsv_as_rtv;
m_state.current_ds_as_rt = ds_as_rt;
}
if (m_state.dsv != dsv)
{
if (m_state.dsv)
@@ -2816,13 +2958,14 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
}
PSUnbindConflictingSRVs(m_state.current_rt, read_only_dsv ? nullptr : m_state.current_ds);
PSUnbindConflictingSRVs(m_state.current_ds_as_rt);
PSUnbindConflictingSRVs(m_state.current_rt_uav, m_state.current_ds_uav);
if (changed)
{
// OM targets and UAVs share the same namespace in DX11, so we need to pack them into contiguous slots.
const u32 num_rtvs = rt ? 1 : 0;
ID3D11RenderTargetView* rtvs[] = {rtv};
const u32 num_rtvs = ds_as_rt ? 2 : rt ? 1 : 0;
ID3D11RenderTargetView* rtvs[] = {rtv, dsv_as_rtv};
if (no_uavs)
m_ctx->OMSetRenderTargets(num_rtvs, rtvs, dsv);
else
@@ -2837,7 +2980,7 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_
}
}
if (rt || ds || rt_uav_tex || ds_uav_tex)
if (rt || ds_as_rt || ds || rt_uav_tex || ds_uav_tex)
{
const GSVector2i size =
rt ? rt->GetSize() :
@@ -2907,6 +3050,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
GSTexture* colclip_rt = g_gs_device->GetColorClipTexture();
GSTexture* draw_rt = config.ps.HasColorROV() ? nullptr : config.rt;
GSTexture* draw_ds_as_rt = m_ds_as_rt;
GSTexture* draw_ds = config.ps.HasDepthROV() ? nullptr : config.ds;
GSTexture* draw_rt_rov = config.ps.HasColorROV() ? config.rt : nullptr;
GSTexture* draw_ds_rov = config.ps.HasDepthROV() ? config.ds : nullptr;
@@ -2947,7 +3091,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
{
config.colclip_update_area = config.drawarea;
colclip_rt = CreateRenderTarget(rtsize.x, rtsize.y, m_rgba16_unorm_hw_blend ? GSTexture::Format::ColorClip : GSTexture::Format::ColorHDR, false);
colclip_rt = CreateFeedbackTarget(rtsize.x, rtsize.y, m_rgba16_unorm_hw_blend ? GSTexture::Format::ColorClip : GSTexture::Format::ColorHDR, false);
if (!colclip_rt)
{
Console.Warning("D3D11: Failed to allocate ColorClip render target, aborting draw.");
@@ -3047,7 +3191,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const OMBlendSelector blend(GSHWDrawConfig::ColorMaskSelector(1),
GSHWDrawConfig::BlendState(true, CONST_ONE, CONST_ONE, 3 /* MIN */, CONST_ONE, CONST_ZERO, false, 0));
SetupOM(dss, blend, 0);
OMSetRenderTargets(primid_texture, config.ds, nullptr, nullptr, &config.scissor, read_only_dsv);
OMSetRenderTargets(primid_texture, nullptr, config.ds, nullptr, nullptr, &config.scissor, read_only_dsv);
SetRenderHWShaderResources(config, nullptr);
Draw(config);
@@ -3059,19 +3203,19 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
// Avoid changing framebuffer just to switch from rt+depth to rt and vice versa.
// Make sure no tex is bound as both rtv and srv at the same time.
// All conflicts should've been taken care of by PSUnbindConflictingSRVs.
if (!(draw_rt || draw_rt_rov) && draw_ds && m_state.current_rt && config.tex != m_state.current_rt && m_state.current_rt->GetSize() == draw_ds->GetSize())
if (!(draw_rt || draw_rt_rov || draw_ds_as_rt) && draw_ds && m_state.current_rt && config.tex != m_state.current_rt && m_state.current_rt->GetSize() == draw_ds->GetSize())
{
draw_rt = m_state.current_rt;
}
else if (!(draw_ds || draw_ds_rov) && draw_rt && m_state.current_ds && config.tex != m_state.current_ds && m_state.current_ds->GetSize() == draw_rt->GetSize())
else if (!(draw_ds || draw_ds_rov || draw_ds_as_rt) && draw_rt && m_state.current_ds && config.tex != m_state.current_ds && m_state.current_ds->GetSize() == draw_rt->GetSize())
{
draw_ds = m_state.current_ds;
}
else if (!(draw_rt || draw_rt_rov) && draw_ds_rov && m_state.current_rt_uav && config.tex != m_state.current_rt_uav)
else if (!(draw_rt || draw_rt_rov || draw_ds_as_rt) && draw_ds_rov && m_state.current_rt_uav && config.tex != m_state.current_rt_uav)
{
draw_rt_rov = m_state.current_rt_uav;
}
else if (!(draw_ds || draw_ds_rov) && draw_rt_rov && m_state.current_ds_uav && config.tex != m_state.current_ds_uav)
else if (!(draw_ds || draw_ds_rov || draw_ds_as_rt) && draw_rt_rov && m_state.current_ds_uav && config.tex != m_state.current_ds_uav)
{
draw_ds_rov = m_state.current_ds_uav;
}
@@ -3090,17 +3234,17 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const bool ds_feedbackloop_pass1 = config.IsFeedbackLoopDepth(config.ps);
const bool ds_feedbackloop_pass2 = config.IsFeedbackLoopDepth(config.alpha_second_pass.ps);
if (draw_ds && !draw_ds_rov && m_features.depth_feedback && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
if (draw_ds && !draw_ds_rov && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
(ds_feedbackloop_pass1 || ds_feedbackloop_pass2))
{
// Requires a copy of the DS.
draw_ds_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_ds->GetFormat(), true);
draw_ds_clone = CreateTexture(rtsize.x, rtsize.y, 1, (draw_ds_as_rt ? draw_ds_as_rt : draw_ds)->GetFormat(), true);
if (!draw_ds_clone)
Console.Warning("D3D11: Failed to allocate temp texture for DS copy.");
}
OMSetRenderTargets(draw_rt, draw_ds, draw_rt_rov, draw_ds_rov, &config.scissor, read_only_dsv);
OMSetRenderTargets(draw_rt, draw_ds_as_rt, draw_ds, draw_rt_rov, draw_ds_rov, &config.scissor, read_only_dsv);
SetRenderHWShaderResources(config, primid_texture);
SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant);
@@ -3108,7 +3252,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && need_barrier)
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(draw_ds), D3D11_CLEAR_STENCIL, 0.0f, 1);
SendHWDraw(config, rt_feedbackloop_pass1 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass1 ? draw_ds_clone : nullptr, draw_ds,
SendHWDraw(config, rt_feedbackloop_pass1 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass1 ? draw_ds_clone : nullptr, draw_ds_as_rt ? draw_ds_as_rt : draw_ds,
config.require_one_barrier, config.require_full_barrier, rtsize);
if (config.blend_multi_pass.enable)
@@ -3136,7 +3280,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const bool one_barrier = config.alpha_second_pass.require_one_barrier && m_features.multidraw_fb_copy;
SetupOM(config.alpha_second_pass.depth, OMBlendSelector(config.alpha_second_pass.colormask, config.blend), config.blend.constant);
SendHWDraw(config, rt_feedbackloop_pass2 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass2 ? draw_ds_clone : nullptr, draw_ds,
SendHWDraw(config, rt_feedbackloop_pass2 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass2 ? draw_ds_clone : nullptr, draw_ds_as_rt ? draw_ds_as_rt : draw_ds,
one_barrier, config.alpha_second_pass.require_full_barrier, rtsize);
}
+21 -2
View File
@@ -93,6 +93,7 @@ private:
VERTEX_BUFFER_SIZE = 32 * 1024 * 1024,
INDEX_BUFFER_SIZE = 16 * 1024 * 1024,
NUM_TIMESTAMP_QUERIES = 5,
NUM_PIPELINE_STATISTICS_QUERIES = 5,
};
void SetFeatures(IDXGIAdapter1* adapter);
@@ -107,6 +108,11 @@ private:
void PopTimestampQuery();
void KickTimestampQuery();
bool CreatePipelineStatisticsQueries();
void DestroyPipelineStatisticsQueries();
void PopPipelineStatisticsQuery();
void KickPipelineStatisticsQuery();
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) override;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
@@ -173,10 +179,12 @@ private:
ID3D11BlendState* bs;
u8 bf;
ID3D11RenderTargetView* rtv;
ID3D11RenderTargetView* dsv_as_rtv;
ID3D11DepthStencilView* dsv;
ID3D11UnorderedAccessView* rt_uav;
ID3D11UnorderedAccessView* ds_uav;
GSTexture* current_rt;
GSTexture* current_ds_as_rt;
GSTexture* current_ds;
GSTexture* current_rt_uav;
GSTexture* current_ds_uav;
@@ -190,6 +198,14 @@ private:
bool m_timestamp_query_started = false;
bool m_gpu_timing_enabled = false;
std::array<wil::com_ptr_nothrow<ID3D11Query>, NUM_PIPELINE_STATISTICS_QUERIES> m_pipeline_statistics_queries = {};
GPUPipelineStatistics m_accumulated_gpu_pipeline_statistics{};
u8 m_read_pipeline_statistics_query = 0;
u8 m_write_pipeline_statistics_query = 0;
u8 m_waiting_pipeline_statistics_queries = 0;
bool m_gpu_pipeline_statistics_enabled = false;
bool m_pipeline_statistics_query_started = false;
struct
{
wil::com_ptr_nothrow<ID3D11InputLayout> il;
@@ -323,6 +339,9 @@ public:
bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
bool SetGPUPipelineStatisticsEnabled(bool enabled) override;
GPUPipelineStatistics GetAndResetAccumulatedGPUPipelineStatistics() override;
// Helpers and utility draws.
void DrawPrimitive();
void DrawIndexedPrimitive();
@@ -337,7 +356,7 @@ public:
void PopDebugGroup() override;
void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) override;
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) override;
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
void CommitClear(GSTexture* t);
@@ -383,7 +402,7 @@ public:
void OMSetDepthStencilState(ID3D11DepthStencilState* dss, u8 sref);
void OMSetBlendState(ID3D11BlendState* bs, u8 bf);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* rt_uav = nullptr, GSTexture* ds_uav = nullptr,
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds_as_rt, GSTexture* ds, GSTexture* rt_uav = nullptr, GSTexture* ds_uav = nullptr,
const GSVector4i* scissor = nullptr, ID3D11DepthStencilView* read_only_dsv = nullptr);
void SetViewport(const GSVector2i& viewport);
void SetScissor(const GSVector4i& scissor);
+4 -2
View File
@@ -12,13 +12,13 @@
#include "fmt/format.h"
GSTexture11::GSTexture11(wil::com_ptr_nothrow<ID3D11Texture2D> texture, const D3D11_TEXTURE2D_DESC& desc,
GSTexture::Type type, GSTexture::Format format)
Usage usage, Format format)
: m_texture(std::move(texture))
, m_desc(desc)
{
m_size.x = static_cast<int>(desc.Width);
m_size.y = static_cast<int>(desc.Height);
m_type = type;
m_usage = usage;
m_format = format;
m_mipmap_levels = static_cast<int>(desc.MipLevels);
}
@@ -102,6 +102,8 @@ void GSTexture11::SetDebugName(std::string_view name)
GSDevice11::SetD3DDebugObjectName(m_srv.get(), fmt::format("{} SRV", name));
if (m_rtv)
GSDevice11::SetD3DDebugObjectName(m_rtv.get(), fmt::format("{} RTV", name));
if (m_uav)
GSDevice11::SetD3DDebugObjectName(m_uav.get(), fmt::format("{} UAV", name));
m_debug_name = name;
}
+1 -1
View File
@@ -21,7 +21,7 @@ class GSTexture11 final : public GSTexture
D3D11_TEXTURE2D_DESC m_desc;
public:
explicit GSTexture11(wil::com_ptr_nothrow<ID3D11Texture2D> texture, const D3D11_TEXTURE2D_DESC& desc,
GSTexture::Type type, GSTexture::Format format);
Usage usage, Format format);
static DXGI_FORMAT GetDXGIFormat(Format format);
+154 -43
View File
@@ -134,6 +134,15 @@ bool GSDevice12::SupportsTextureFormat(DXGI_FORMAT format)
(support.Support1 & required) == required;
}
bool GSDevice12::IsTextureFormatUAVCapable(DXGI_FORMAT format)
{
constexpr u32 required = D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW;
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = { format };
return SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
(support.Support1 & required) == required;
}
bool GSDevice12::SupportsProgrammableSamplePositions()
{
D3D12_FEATURE_DATA_D3D12_OPTIONS2 options = {};
@@ -510,6 +519,39 @@ void GSDevice12::MoveToNextCommandList()
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST);
}
if (res.pipeline_statistics_query == QueryState::Ready)
{
// Collect the pipeline statistics from the last time this cmdlist was used.
res.pipeline_statistics_query = QueryState::None;
const u32 offset = (m_current_command_list * sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS));
const D3D12_RANGE read_range = { offset, offset + sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) };
void* map;
HRESULT hr = m_pipeline_statistics_query_buffer->Map(0, &read_range, &map);
if (SUCCEEDED(hr))
{
D3D12_QUERY_DATA_PIPELINE_STATISTICS stats;
std::memcpy(&stats, static_cast<const u8*>(map) + offset, sizeof(stats));
m_accumulated_gpu_pipeline_statistics.vs_invocations += stats.VSInvocations;
m_accumulated_gpu_pipeline_statistics.ps_invocations += stats.PSInvocations;
const D3D12_RANGE write_range = {};
m_pipeline_statistics_query_buffer->Unmap(0, &write_range);
}
else
{
Console.Warning("D3D12: Map() for pipeline statistics query failed: %08X", hr);
}
}
if (m_gpu_pipeline_statistics_enabled)
{
pxAssert(res.pipeline_statistics_query == QueryState::None);
res.pipeline_statistics_query = QueryState::Querying;
res.command_lists[1].list4->BeginQuery(
m_pipeline_statistics_query_heap.get(), D3D12_QUERY_TYPE_PIPELINE_STATISTICS, m_current_command_list);
}
ID3D12DescriptorHeap* heaps[2] = {
res.descriptor_allocator.GetDescriptorHeap(), res.sampler_allocator.GetDescriptorHeap()};
res.command_lists[1].list4->SetDescriptorHeaps(std::size(heaps), heaps);
@@ -555,6 +597,18 @@ bool GSDevice12::ExecuteCommandList(WaitType wait_for_completion)
m_timestamp_query_buffer.get(), m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
}
if ((res.pipeline_statistics_query == QueryState::Querying) || (res.pipeline_statistics_query == QueryState::Ready))
{
if (res.pipeline_statistics_query == QueryState::Querying)
{
// Didn't end query in BeginPresent() so end it here.
res.pipeline_statistics_query = QueryState::Ready;
res.command_lists[1].list4->EndQuery(m_pipeline_statistics_query_heap.get(), D3D12_QUERY_TYPE_PIPELINE_STATISTICS, m_current_command_list);
}
res.command_lists[1].list4->ResolveQueryData(m_pipeline_statistics_query_heap.get(), D3D12_QUERY_TYPE_PIPELINE_STATISTICS,
m_current_command_list, 1, m_pipeline_statistics_query_buffer.get(), m_current_command_list * sizeof(D3D11_QUERY_DATA_PIPELINE_STATISTICS));
}
if (res.init_command_list_used)
{
hr = res.command_lists[0].list4->Close();
@@ -707,6 +761,36 @@ void GSDevice12::WaitForGPUIdle()
}
}
bool GSDevice12::CreatePipelineStatisticsQuery()
{
constexpr u32 QUERY_COUNT = NUM_COMMAND_LISTS;
constexpr u32 BUFFER_SIZE = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) * QUERY_COUNT;
const D3D12_QUERY_HEAP_DESC desc = { D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS, QUERY_COUNT };
HRESULT hr = m_device->CreateQueryHeap(&desc, IID_PPV_ARGS(m_pipeline_statistics_query_heap.put()));
if (FAILED(hr))
{
Console.Error("D3D12: CreateQueryHeap() for pipeline statistics failed with %08X", hr);
return false;
}
const D3D12MA::ALLOCATION_DESC allocation_desc = { D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_READBACK };
const D3D12_RESOURCE_DESCU resource_desc = { {D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1,
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE} };
if (m_enhanced_barriers)
hr = m_allocator->CreateResource3(&allocation_desc, &resource_desc.desc1, D3D12_BARRIER_LAYOUT_UNDEFINED, nullptr,
0, nullptr, m_pipeline_statistics_query_allocation.put(), IID_PPV_ARGS(m_pipeline_statistics_query_buffer.put()));
else
hr = m_allocator->CreateResource(&allocation_desc, &resource_desc.desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
m_pipeline_statistics_query_allocation.put(), IID_PPV_ARGS(m_pipeline_statistics_query_buffer.put()));
if (FAILED(hr))
{
Console.Error("D3D12: CreateResource() for pipeline statistics failed with %08X", hr);
return false;
}
return true;
}
bool GSDevice12::CreateTimestampQuery()
{
constexpr u32 QUERY_COUNT = NUM_TIMESTAMP_QUERIES_PER_CMDLIST * NUM_COMMAND_LISTS;
@@ -760,6 +844,19 @@ bool GSDevice12::SetGPUTimingEnabled(bool enabled)
return true;
}
GPUPipelineStatistics GSDevice12::GetAndResetAccumulatedGPUPipelineStatistics()
{
GPUPipelineStatistics stats = m_accumulated_gpu_pipeline_statistics;
m_accumulated_gpu_pipeline_statistics = {};
return stats;
}
bool GSDevice12::SetGPUPipelineStatisticsEnabled(bool enabled)
{
m_gpu_pipeline_statistics_enabled = enabled;
return true;
}
bool GSDevice12::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer,
D3D12MA::Allocation** gpu_allocation, const std::function<void(void*)>& fill_callback)
{
@@ -854,7 +951,7 @@ bool GSDevice12::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
m_name = D3D::GetAdapterName(m_adapter.get());
if (!CreateDescriptorHeaps() || !CreateCommandLists() || !CreateTimestampQuery())
if (!CreateDescriptorHeaps() || !CreateCommandLists() || !CreateTimestampQuery() || !CreatePipelineStatisticsQuery())
return false;
if (!AcquireWindow(true) || (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain()))
@@ -1093,7 +1190,7 @@ bool GSDevice12::CreateSwapChainRTV()
return false;
}
std::unique_ptr<GSTexture12> tex = GSTexture12::Adopt(std::move(backbuffer), GSTexture::Type::RenderTarget,
std::unique_ptr<GSTexture12> tex = GSTexture12::Adopt(std::move(backbuffer), GSTexture::RenderTarget,
GSTexture::Format::Color, swap_chain_desc.BufferDesc.Width, swap_chain_desc.BufferDesc.Height, 1,
swap_chain_desc.BufferDesc.Format, DXGI_FORMAT_UNKNOWN, swap_chain_desc.BufferDesc.Format,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, GSTexture12::ResourceState::Present);
@@ -1266,6 +1363,14 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip)
return PresentResult::FrameSkipped;
}
// End the pipeline statistics for this cmdlist before postprocessing.
CommandListResources& res = m_command_lists[m_current_command_list];
if (res.pipeline_statistics_query == QueryState::Querying)
{
res.pipeline_statistics_query = QueryState::Ready;
res.command_lists[1].list4->EndQuery(m_pipeline_statistics_query_heap.get(), D3D12_QUERY_TYPE_PIPELINE_STATISTICS, m_current_command_list);
}
GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get();
const D3D12CommandList& cmdlist = GetCommandList();
@@ -1441,6 +1546,16 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id)
D3D12_FEATURE_DATA_D3D12_OPTIONS options{};
m_device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS));
m_features.rov = options.ROVsSupported;
for (u32 fmt = static_cast<u32>(GSTexture::Format::Color); fmt <= static_cast<u32>(GSTexture::Format::PrimID); fmt++)
{
if (GSTexture::IsShaderWriteFormat(static_cast<GSTexture::Format>(fmt)))
{
DXGI_FORMAT dxgi_fmt;
LookupNativeFormat(static_cast<GSTexture::Format>(fmt), &dxgi_fmt, nullptr, nullptr, nullptr, nullptr);
m_features.rov &= IsTextureFormatUAVCapable(dxgi_fmt);
}
}
Console.WriteLnFmt("D3D12: Rasterizer Ordered Views: {}", m_features.rov ? "Supported" : "Not Supported");
Console.WriteLnFmt("D3D12: Tight Alignment: {}", m_allocator->IsTightAlignmentSupported() ? "Supported" : "Not Supported");
return true;
@@ -1538,22 +1653,22 @@ void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_f
*uav_format = mapping[4];
}
GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
GSTexture* GSDevice12::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
{
DXGI_FORMAT dxgi_format, srv_format, rtv_format, dsv_format, uav_format;
LookupNativeFormat(format, &dxgi_format, &srv_format, &rtv_format, &dsv_format, &uav_format);
if (type != GSTexture::Type::RWTexture && type != GSTexture::Type::RenderTarget)
if (!GSTexture::IsShaderWrite(usage))
uav_format = DXGI_FORMAT_UNKNOWN; // We don't need the UAV descriptor.
std::unique_ptr<GSTexture12> tex(GSTexture12::Create(type, format, width, height, levels,
std::unique_ptr<GSTexture12> tex(GSTexture12::Create(usage, format, width, height, levels,
dxgi_format, srv_format, rtv_format, dsv_format, uav_format));
if (!tex)
{
// We're probably out of vram, try flushing the command buffer to release pending textures.
PurgePool();
ExecuteCommandListAndRestartRenderPass(true, "Couldn't allocate texture.");
tex = GSTexture12::Create(type, format, width, height, levels, dxgi_format, srv_format,
tex = GSTexture12::Create(usage, format, width, height, levels, dxgi_format, srv_format,
rtv_format, dsv_format, uav_format);
}
@@ -1602,7 +1717,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
dTex12->SetState(GSTexture::State::Dirty);
if (dTex12->GetType() != GSTexture::Type::DepthStencil)
if (!dTex12->IsDepthStencil())
{
dTex12->TransitionToState(GSTexture12::ResourceState::RenderTarget);
GetCommandList().list4->ClearRenderTargetView(
@@ -1634,7 +1749,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
sTex12->TransitionToState(GSTexture12::ResourceState::CopySrc);
sTex12->SetUseFenceCounter(GetCurrentFenceValue());
if (m_tfx_textures[0] && sTex12->GetSRVDescriptor() == m_tfx_textures[0])
PSSetShaderResource(0, nullptr, false);
PSSetShaderResource(TEXTURE_TEXTURE, nullptr, false);
dTex12->TransitionToState(GSTexture12::ResourceState::CopyDst);
dTex12->SetUseFenceCounter(GetCurrentFenceValue());
@@ -1890,7 +2005,7 @@ void GSDevice12::BeginRenderPassForStretchRect(
GetLoadOpForTexture(dTex);
dTex->SetState(GSTexture::State::Dirty);
if (dTex->GetType() != GSTexture::Type::DepthStencil)
if (!dTex->IsDepthStencil())
{
BeginRenderPass(load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
@@ -1921,7 +2036,7 @@ void GSDevice12::DoStretchRect(GSTexture12* sTex, const GSVector4& sRect, GSText
SetPipeline(pipeline);
const bool is_present = (!dTex);
const bool depth = (dTex && dTex->GetType() == GSTexture::Type::DepthStencil);
const bool depth = (dTex && dTex->IsDepthStencil());
const GSVector2i size(is_present ? GSVector2i(GetWindowWidth(), GetWindowHeight()) : dTex->GetSize());
const GSVector4i dtex_rc(0, 0, size.x, size.y);
const GSVector4i dst_rc(GSVector4i(dRect).rintersect(dtex_rc));
@@ -2604,9 +2719,11 @@ GSDevice12::ComPtr<ID3DBlob> GSDevice12::GetUtilityPixelShader(const std::string
bool GSDevice12::CreateNullTexture()
{
const GSTexture::Usage null_access = m_features.rov ? GSTexture::ShaderWriteTarget : GSTexture::FeedbackTarget;
const DXGI_FORMAT null_uav_format = m_features.rov ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_UNKNOWN;
m_null_texture =
GSTexture12::Create(GSTexture::Type::RenderTarget, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM);
GSTexture12::Create(null_access, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, null_uav_format);
if (!m_null_texture)
return false;
@@ -3070,6 +3187,8 @@ void GSDevice12::DestroyResources()
m_timestamp_query_buffer.reset();
m_timestamp_query_allocation.reset();
m_pipeline_statistics_query_buffer.reset();
m_pipeline_statistics_query_allocation.reset();
m_sampler_heap_manager.Destroy();
m_dsv_heap_manager.Destroy();
m_rtv_heap_manager.Destroy();
@@ -3117,6 +3236,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
ShaderMacro sm;
sm.AddMacro("PIXEL_SHADER", 1);
sm.AddMacro("PS_HAS_CONSERVATIVE_DEPTH", 1);
sm.AddMacro("PS_DEPTH_FEEDBACK_SUPPORT", 2);
sm.AddMacro("PS_FST", sel.fst);
sm.AddMacro("PS_WMS", sel.wms);
sm.AddMacro("PS_WMT", sel.wmt);
@@ -3526,15 +3646,10 @@ void GSDevice12::PSSetSampler(GSHWDrawConfig::SamplerSelector sel)
m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS;
}
void GSDevice12::PSSetUnorderedAccess(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds)
void GSDevice12::PSSetROVs(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds)
{
GSTexture12* d12Rt = static_cast<GSTexture12*>(rt);
GSTexture12* d12Ds = static_cast<GSTexture12*>(ds);
GSTexture12* oldD12Rt = m_tfx_textures_uav[0] != m_null_texture.get() ? m_tfx_textures_uav[0] : nullptr;
GSTexture12* oldD12Ds = m_tfx_textures_uav[1] != m_null_texture.get() ? m_tfx_textures_uav[1] : nullptr;
if (!(d12Rt || d12Ds || oldD12Rt || oldD12Ds))
return;
pxAssert(!(d12Rt || d12Ds) || m_features.rov);
@@ -3672,9 +3787,8 @@ void GSDevice12::UnbindTexture(GSTexture12* tex)
// RT UAV / depth UAV
for (u32 i = TEXTURE_RT_UAV; i <= TEXTURE_DEPTH_UAV; i++)
{
if (m_tfx_textures_uav[i - TEXTURE_RT_UAV] == tex)
if (m_tfx_textures[i] == tex->GetUAVDescriptor())
{
m_tfx_textures_uav[i - TEXTURE_RT_UAV] = nullptr;
m_tfx_textures[i] = m_null_texture->GetUAVDescriptor();
m_dirty_flags |= DIRTY_FLAG_TFX_RT_TEXTURES;
}
@@ -4226,7 +4340,7 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe
// and bind the image to the primitive sampler
image->TransitionToState(GSTexture12::ResourceState::PixelShaderResource);
PSSetShaderResource(3, image, false);
PSSetShaderResource(TEXTURE_PRIMID, image, false);
return image;
}
@@ -4344,11 +4458,11 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// bind textures before checking the render pass, in case we need to transition them
if (config.tex)
{
PSSetShaderResource(0, config.tex, config.tex != config.rt && config.tex != config.ds);
PSSetShaderResource(TEXTURE_TEXTURE, config.tex, config.tex != config.rt && config.tex != config.ds);
PSSetSampler(config.sampler);
}
if (config.pal)
PSSetShaderResource(1, config.pal, true);
PSSetShaderResource(TEXTURE_PALETTE, config.pal, true);
if (config.blend.constant_enable)
SetBlendConstants(config.blend.constant);
@@ -4377,7 +4491,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
EndRenderPass();
colclip_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
colclip_rt = static_cast<GSTexture12*>(CreateFeedbackTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
if (!colclip_rt)
{
Console.Warning("D3D12: Failed to allocate ColorClip render target, aborting draw.");
@@ -4404,7 +4518,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// we're not drawing to the RT, so we can use it as a source
if (config.require_one_barrier && !m_features.texture_barrier)
PSSetShaderResource(2, draw_rt, true);
PSSetShaderResource(TEXTURE_RT, draw_rt, true);
}
draw_rt = colclip_rt;
@@ -4413,21 +4527,18 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// Clear texture binding when it's bound to RT or DS.
if (!config.tex && ((draw_rt && static_cast<GSTexture12*>(draw_rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
(draw_ds && static_cast<GSTexture12*>(draw_ds)->GetSRVDescriptor() == m_tfx_textures[0])))
PSSetShaderResource(0, nullptr, false);
PSSetShaderResource(TEXTURE_TEXTURE, nullptr, false);
if (InRenderPass() && (m_current_render_target == draw_rt || m_current_depth_target == draw_ds))
// Avoid restarting the render pass just to switch from rt+depth to rt and vice versa.
// Keep the depth even if doing colclip hw draws, because the next draw will probably re-enable depth.
if (InRenderPass() && !(draw_rt || draw_rt_rov) && draw_ds && m_current_render_target && config.tex != m_current_render_target &&
m_current_render_target->GetSize() == draw_ds->GetSize())
{
// avoid restarting the render pass just to switch from rt+depth to rt and vice versa
// keep the depth even if doing colclip hw draws, because the next draw will probably re-enable depth
if (!(draw_rt || draw_rt_rov) && m_current_render_target && config.tex != m_current_render_target &&
draw_ds && m_current_render_target->GetSize() == draw_ds->GetSize())
{
draw_rt = m_current_render_target;
m_pipeline_selector.rt = true;
}
draw_rt = m_current_render_target;
m_pipeline_selector.rt = true;
}
else if (!(draw_ds || draw_ds_rov) && m_current_depth_target && config.tex != m_current_depth_target &&
draw_rt && m_current_depth_target->GetSize() == draw_rt->GetSize())
else if (InRenderPass() && !(draw_ds || draw_ds_rov) && draw_rt && m_current_depth_target && config.tex != m_current_depth_target &&
m_current_depth_target->GetSize() == draw_rt->GetSize())
{
draw_ds = m_current_depth_target;
m_pipeline_selector.ds = true;
@@ -4475,15 +4586,15 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt_clone, true);
PSSetShaderResource(TEXTURE_RT, draw_rt_clone, true);
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt_clone, true);
PSSetShaderResource(TEXTURE_TEXTURE, draw_rt_clone, true);
}
else
Console.Warning("D3D12: Failed to allocate temp texture for RT copy.");
}
PSSetUnorderedAccess(draw_rt_rov, draw_ds_rov, config.ps.HasColorOutput(), config.ps.HasDepthROVWrite());
PSSetROVs(draw_rt_rov, draw_ds_rov, config.ps.HasColorOutput(), config.ps.HasDepthROVWrite());
// For depth testing and sampling, use a read only dsv, otherwise use a write dsv
OMSetRenderTargets(draw_rt, draw_ds_as_rt, draw_ds, config.scissor,
@@ -4649,11 +4760,11 @@ void GSDevice12::SendHWDraw(const PipelineSelector& pipe, const GSHWDrawConfig&
Console.Warning("D3D12: Possible unnecessary barrier detected.");
#endif
if ((one_barrier || full_barrier) && feedback_rt)
PSSetShaderResource(2, draw_rt, false, ResourceType::FBL);
PSSetShaderResource(TEXTURE_RT, draw_rt, false, ResourceType::FBL);
if (config.tex_hazard == GSHWDrawConfig::TEX_HAZARD_RT)
PSSetShaderResource(0, draw_rt, false, ResourceType::FBL);
PSSetShaderResource(TEXTURE_TEXTURE, draw_rt, false, ResourceType::FBL);
if ((one_barrier || full_barrier) && feedback_depth)
PSSetShaderResource(4, draw_ds, false, ResourceType::FBL);
PSSetShaderResource(TEXTURE_DEPTH, draw_ds, false, ResourceType::FBL);
if (full_barrier)
{
+24 -4
View File
@@ -152,6 +152,9 @@ public:
/// Test for support for the specified texture format.
bool SupportsTextureFormat(DXGI_FORMAT format);
/// Test for UAV support for the specified texture format.
bool IsTextureFormatUAVCapable(DXGI_FORMAT format);
// Partial depth copies require ProgrammableSamplePositions tier 1.
bool SupportsProgrammableSamplePositions();
@@ -188,6 +191,14 @@ public:
void UploadIndices(D3D12StreamBuffer& buffer, const void* index, size_t count);
private:
// For pipeline statistics
enum class QueryState
{
None,
Querying,
Ready,
};
struct CommandListResources
{
std::array<ComPtr<ID3D12CommandAllocator>, 2> command_allocators;
@@ -199,6 +210,7 @@ private:
u64 ready_fence_value = 0;
bool init_command_list_used = false;
bool has_timestamp_query = false;
QueryState pipeline_statistics_query = QueryState::None;
};
void LoadAgilitySDK();
@@ -207,6 +219,7 @@ private:
bool CreateDescriptorHeaps();
bool CreateCommandLists();
bool CreateTimestampQuery();
bool CreatePipelineStatisticsQuery();
void MoveToNextCommandList();
void DestroyPendingResources(CommandListResources& cmdlist);
@@ -231,6 +244,12 @@ private:
bool m_gpu_timing_enabled = false;
bool m_programmable_sample_positions = false;
ComPtr<ID3D12QueryHeap> m_pipeline_statistics_query_heap;
ComPtr<ID3D12Resource> m_pipeline_statistics_query_buffer;
ComPtr<D3D12MA::Allocation> m_pipeline_statistics_query_allocation;
GPUPipelineStatistics m_accumulated_gpu_pipeline_statistics{};
bool m_gpu_pipeline_statistics_enabled = false;
D3D12DescriptorHeapManager m_descriptor_heap_manager;
D3D12DescriptorHeapManager m_rtv_heap_manager;
D3D12DescriptorHeapManager m_dsv_heap_manager;
@@ -431,8 +450,7 @@ private:
void DestroySwapChainRTVs();
void DestroySwapChain();
GSTexture* CreateSurface(
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) final;
@@ -508,6 +526,9 @@ public:
bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
bool SetGPUPipelineStatisticsEnabled(bool enabled) override;
GPUPipelineStatistics GetAndResetAccumulatedGPUPipelineStatistics() override;
void PushDebugGroup(const char* fmt, ...) override;
void PopDebugGroup() override;
void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) override;
@@ -553,7 +574,7 @@ public:
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, ResourceType type = ResourceType::SRV);
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
void PSSetUnorderedAccess(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds);
void PSSetROVs(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, GSTexture* ds_as_rt, const GSVector4i& scissor,
bool depth_read = false, const GSVector2i& viewport_size = {});
@@ -696,7 +717,6 @@ private:
std::array<D3D12_GPU_VIRTUAL_ADDRESS, NUM_TFX_CONSTANT_BUFFERS> m_tfx_constant_buffers{};
std::array<D3D12DescriptorHandle, NUM_TOTAL_TFX_TEXTURES> m_tfx_textures{};
std::array<GSTexture12*, NUM_TFX_UAV_TEXTURES> m_tfx_textures_uav{};
D3D12DescriptorHandle m_tfx_sampler;
u32 m_tfx_sampler_sel = 0;
D3D12DescriptorHandle m_tfx_textures_handle_gpu;
+85 -106
View File
@@ -14,7 +14,7 @@
#include "D3D12MemAlloc.h"
GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
GSTexture12::GSTexture12(Usage usage, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
@@ -33,7 +33,7 @@ GSTexture12::GSTexture12(Type type, Format format, int width, int height, int le
, m_resource_state(resource_state)
, m_simultaneous_tex(simultaneous_texture)
{
m_type = type;
m_usage = usage;
m_format = format;
m_size.x = width;
m_size.y = height;
@@ -175,10 +175,12 @@ static D3D12_RESOURCE_STATES GetD3D12ResourceState(GSTexture12::ResourceState st
}
}
std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int width, int height, int levels,
std::unique_ptr<GSTexture12> GSTexture12::Create(Usage usage, Format format, int width, int height, int levels,
DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format,
DXGI_FORMAT uav_format)
{
pxAssert(ValidateUsageAndFormat(usage, format));
GSDevice12* const dev = GSDevice12::GetInstance();
GSDevice12::D3D12_RESOURCE_DESCU desc = {};
@@ -198,67 +200,55 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
D3D12_CLEAR_VALUE optimized_clear_value = {};
ResourceState state;
switch (type)
if (IsTexture(usage))
{
case Type::Texture:
{
// This is a little annoying. basically, to do mipmap generation, we need to be a render target.
// If it's a compressed texture, we won't be generating mips anyway, so this should be fine.
desc.desc1.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
D3D12_RESOURCE_FLAG_NONE;
state = ResourceState::CopyDst;
pxAssert(uav_format == DXGI_FORMAT_UNKNOWN);
}
break;
// This is a little annoying. basically, to do mipmap generation, we need to be a render target.
// If it's a compressed texture, we won't be generating mips anyway, so this should be fine.
desc.desc1.Flags |= (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
D3D12_RESOURCE_FLAG_NONE;
state = ResourceState::CopyDst;
}
else
{
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
}
case Type::RenderTarget:
{
// RT's tend to be larger, so we'll keep them committed for speed.
pxAssert(levels == 1);
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
allocationDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
if (!dev->UseEnhancedBarriers())
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
optimized_clear_value.Format = rtv_format;
state = ResourceState::RenderTarget;
if (uav_format != DXGI_FORMAT_UNKNOWN)
{
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
}
break;
if (IsRenderTarget(usage))
{
// RT's tend to be larger, so we'll keep them committed for speed.
pxAssert(levels == 1);
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
optimized_clear_value.Format = rtv_format;
state = ResourceState::RenderTarget;
}
case Type::DepthStencil:
{
pxAssert(levels == 1);
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
optimized_clear_value.Format = dsv_format;
state = ResourceState::DepthWriteStencil;
pxAssert(uav_format == DXGI_FORMAT_UNKNOWN);
}
break;
if (IsFeedback(usage))
{
allocationDesc.ExtraHeapFlags |= D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
if (!dev->UseEnhancedBarriers())
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
}
case Type::RWTexture:
{
pxAssert(levels == 1);
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
state = ResourceState::PixelShaderResource;
pxAssert(uav_format != DXGI_FORMAT_UNKNOWN);
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
break;
if (IsDepthStencil(usage))
{
pxAssert(levels == 1);
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
optimized_clear_value.Format = dsv_format;
state = ResourceState::DepthWriteStencil;
}
default:
return {};
if (IsShaderWrite(usage))
{
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
state = ResourceState::PixelShaderResource;
}
wil::com_ptr_nothrow<ID3D12Resource> resource;
wil::com_ptr_nothrow<ID3D12Resource> resource_fbl;
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
if (type == Type::RenderTarget && !dev->UseEnhancedBarriers())
if (IsFeedback(usage) && !dev->UseEnhancedBarriers())
{
// We need to use an aliased resource for feedback with legacy barriers.
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo = dev->GetDevice()->GetResourceAllocationInfo(0, 1, &desc.desc);
@@ -301,14 +291,14 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
if (dev->UseEnhancedBarriers())
{
hr = dev->GetAllocator()->CreateResource3(&allocationDesc, &desc.desc1,
type == Type::RenderTarget ? D3D12_BARRIER_LAYOUT_COMMON : GetD3D12BarrierLayout(state),
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
IsFeedback(usage) ? D3D12_BARRIER_LAYOUT_COMMON : GetD3D12BarrierLayout(state),
IsRenderTargetOrDepthStencil(usage) ? &optimized_clear_value : nullptr,
0, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
}
else
{
hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc.desc, GetD3D12ResourceState(state),
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
IsRenderTargetOrDepthStencil(usage) ? &optimized_clear_value : nullptr, allocation.put(),
IID_PPV_ARGS(resource.put()));
}
if (FAILED(hr))
@@ -329,51 +319,39 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
return {};
}
switch (type)
if (IsRenderTarget(usage))
{
case Type::RenderTarget:
write_descriptor_type = WriteDescriptorType::RTV;
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
{
write_descriptor_type = WriteDescriptorType::RTV;
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
{
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
{
dev->GetRTVHeapManager().Free(&write_descriptor);
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
break;
}
case Type::DepthStencil:
if (IsDepthStencil(usage))
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
{
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
{
dev->GetDSVHeapManager().Free(&write_descriptor);
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
break;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
{
dev->GetDSVHeapManager().Free(&write_descriptor);
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
}
case Type::RWTexture:
{
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
{
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
}
break;
pxAssert(IsShaderWrite(usage) == (uav_format != DXGI_FORMAT_UNKNOWN));
if (IsShaderWrite(usage) && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
{
if (IsRenderTarget(usage))
dev->GetRTVHeapManager().Free(&write_descriptor);
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
// Feedback descriptor used with legacy barriers
@@ -401,11 +379,11 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
}
return std::unique_ptr<GSTexture12>(
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, type == Type::RenderTarget, state));
new GSTexture12(usage, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, IsFeedback(usage), 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, Usage usage, Format format,
int width, int height, int levels, DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, ResourceState resource_state)
{
@@ -419,7 +397,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
return {};
}
if (type == Type::RenderTarget)
if (IsRenderTarget(usage))
{
write_descriptor_type = WriteDescriptorType::RTV;
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
@@ -428,7 +406,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
return {};
}
}
else if (type == Type::DepthStencil)
else if (IsDepthStencil(usage))
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
@@ -444,7 +422,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
}
}
if (uav_format != DXGI_FORMAT_UNKNOWN)
pxAssert(IsShaderWrite(usage) == (uav_format != DXGI_FORMAT_UNKNOWN));
if (IsShaderWrite(usage))
{
if (!CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
{
@@ -466,7 +445,7 @@ 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(usage, format, static_cast<u32>(desc.Width), desc.Height,
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, {}, uav_descriptor,
{}, write_descriptor_type, false, resource_state));
}
@@ -535,7 +514,7 @@ void* GSTexture12::GetNativeHandle() const
const D3D12CommandList& GSTexture12::GetCommandBufferForUpdate()
{
GSDevice12* const dev = GSDevice12::GetInstance();
if (m_type != Type::Texture || m_use_fence_counter == dev->GetCurrentFenceValue())
if (!IsTexture() || m_use_fence_counter == dev->GetCurrentFenceValue())
{
// Console.WriteLn("Texture update within frame, can't use do beforehand");
GSDevice12::GetInstance()->EndRenderPass();
@@ -661,7 +640,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
TransitionSubresourceToState(cmdlist, layer, m_resource_state, GSTexture12::ResourceState::CopyDst);
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
if (m_type == Type::RenderTarget)
if (IsRenderTarget())
{
if (!r.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
CommitClear(cmdlist);
@@ -681,7 +660,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
if (m_resource_state != GSTexture12::ResourceState::CopyDst)
TransitionSubresourceToState(cmdlist, layer, GSTexture12::ResourceState::CopyDst, m_resource_state);
if (m_type == Type::Texture)
if (IsTexture())
m_needs_mipmaps_generated |= (layer == 0);
return true;
@@ -740,7 +719,7 @@ void GSTexture12::Unmap()
TransitionSubresourceToState(cmdlist, m_map_level, m_resource_state, ResourceState::CopyDst);
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
if (m_type == Type::RenderTarget)
if (IsRenderTarget())
{
if (!m_map_area.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
CommitClear(cmdlist);
@@ -769,7 +748,7 @@ void GSTexture12::Unmap()
if (m_resource_state != ResourceState::CopyDst)
TransitionSubresourceToState(cmdlist, m_map_level, ResourceState::CopyDst, m_resource_state);
if (m_type == Type::Texture)
if (IsTexture())
m_needs_mipmaps_generated |= (m_map_level == 0);
}
+4 -4
View File
@@ -39,10 +39,10 @@ public:
~GSTexture12() override;
static std::unique_ptr<GSTexture12> Create(Type type, Format format, int width, int height, int levels,
static std::unique_ptr<GSTexture12> Create(Usage usage, Format format, int width, int height, int levels,
DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format,
DXGI_FORMAT uav_format);
static std::unique_ptr<GSTexture12> Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
static std::unique_ptr<GSTexture12> Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Usage usage, Format format,
int width, int height, int levels, DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, ResourceState resource_state);
@@ -56,7 +56,7 @@ public:
__fi ID3D12Resource* GetResource() const { return m_resource.get(); }
__fi ID3D12Resource* GetFBLResource() const { return m_resource_fbl.get(); }
virtual bool IsUnorderedAccess() const override { return GetResourceState() == ResourceState::PixelShaderUAV; }
bool IsShaderWriteMode() const override { return GetResourceState() == ResourceState::PixelShaderUAV; }
void* GetNativeHandle() const override;
@@ -90,7 +90,7 @@ private:
DSV
};
GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
GSTexture12(Usage usage, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
+3 -3
View File
@@ -1135,9 +1135,9 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
rt_again->m_valid.y /= 2;
rt_again->m_valid.w /= 2;
rt_again->m_TEX0.PSM = PSMCT32;
GSTexture* tex = g_gs_device->CreateRenderTarget(
rt_again->m_unscaled_size.x * rt_again->m_scale, rt_again->m_unscaled_size.y * rt_again->m_scale,
GSTexture::Format::Color, false);
GSTexture* tex = g_gs_device->CreateCompatible(rt_again->m_texture,
static_cast<int>(rt_again->m_unscaled_size.x * rt_again->m_scale),
static_cast<int>(rt_again->m_unscaled_size.y * rt_again->m_scale), false);
if (!tex)
return false;
+132 -118
View File
@@ -1353,14 +1353,14 @@ GSVector4 GSRendererHW::RealignTargetTextureCoordinate(const GSTextureCache::Sou
GSVector4i GSRendererHW::ComputeBoundingBoxRT(const GSVector2i& rtsize, float rtscale)
{
const GSVector4 offset = GSVector4(-1.0f, 1.0f); // Round value
const GSVector4 offset = IsCoverageAlphaSupported() ? GSVector4(-2.0f, 2.0f) : GSVector4(-1.0f, 1.0f); // Round value
const GSVector4 box = m_vt.m_min.p.upld(m_vt.m_max.p) + offset.xxyy();
return GSVector4i(box * GSVector4(rtscale)).rintersect(GSVector4i(0, 0, rtsize.x, rtsize.y));
}
GSVector4i GSRendererHW::ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& coverage, const GSVector4i& region, float texscale)
{
const GSVector4 offset = GSVector4(region.xyxy()) + GSVector4(-1.0f, -1.0f, 1.0f, 1.0f); // Region offset + round value
const GSVector4 offset = GSVector4(region.xyxy()) + (IsCoverageAlphaSupported() ? GSVector4(-2.0f, -2.0f, 2.0f, 2.0f) : GSVector4(-1.0f, -1.0f, 1.0f, 1.0f)); // Region offset + round value
const GSVector4 box = GSVector4(coverage) + offset;
return GSVector4i(box * GSVector4(texscale)).rintersect(GSVector4i(0, 0, texsize.x, texsize.y));
}
@@ -5442,6 +5442,25 @@ void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert
GL_INS("HW: AA1 line expand.");
m_conf.vs.expand = GSHWDrawConfig::VSExpand::LineAA1;
m_conf.cb_vs.point_size = GSVector2(16.0f * sx, 16.0f * sy);
if (target_scale == 1.0f)
{
m_conf.cb_vs.line_aa1_width = 1.0f; // 1 native pixel on each side.
m_conf.cb_ps.LineCovScale = 1.0f; // Linear falloff on both sides.
}
else
{
// Reduce the amount of blur with upscaling.
constexpr float half_native_px = 0.5f;
const float upscaled_px = 1.0f / target_scale;
// Half a native pixel + 1 upscaled pixel on both sides.
m_conf.cb_vs.line_aa1_width = half_native_px + upscaled_px;
// Opaque in middle and linear falloff on last 2 upscaled pixels on each side.
m_conf.cb_ps.LineCovScale = (half_native_px + upscaled_px) / (2 * upscaled_px);
}
m_conf.topology = GSHWDrawConfig::Topology::Triangle;
m_conf.indices_per_prim = 6;
ExpandLineIndices();
@@ -5583,7 +5602,7 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds)
// No interpolation for flat Z so we can make some optimizations.
const bool flat_z = m_vt.m_eq.z || m_vt.m_primclass == GS_POINT_CLASS || m_vt.m_primclass == GS_SPRITE_CLASS;
m_conf.cb_vs.max_depth = GSVector2i(0xFFFFFFFF);
m_conf.cb_vs.max_depth = 0xFFFFFFFF;
m_conf.cb_ps.TA_MaxDepth_Af.z = 0.0f;
m_conf.ps.zclamp = false;
@@ -5597,7 +5616,7 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds)
if (flat_z)
{
// Clamp in vertex shader.
m_conf.cb_vs.max_depth = GSVector2i(max_z);
m_conf.cb_vs.max_depth = max_z;
}
else
{
@@ -5881,10 +5900,12 @@ void GSRendererHW::EmulateDATESelectMethod(DATEOptions& date_options, GSTextureC
const GSDevice::FeatureSupport& features = g_gs_device->Features();
// Date one can run with complex alpha test if there's no overlap.
const bool complex_alpha_test = m_cached_ctx.TEST.ATE &&
m_cached_ctx.TEST.ATST != ATST_ALWAYS &&
m_cached_ctx.TEST.ATST != ATST_NEVER &&
m_cached_ctx.TEST.AFAIL != AFAIL_KEEP;
m_cached_ctx.TEST.AFAIL != AFAIL_KEEP &&
m_prim_overlap != PRIM_OVERLAP_NO;
if (m_cached_ctx.TEST.DATM)
{
blend_alpha_min = std::max(blend_alpha_min, 128);
@@ -5927,9 +5948,15 @@ void GSRendererHW::EmulateDATESelectMethod(DATEOptions& date_options, GSTextureC
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
else if (m_conf.colormask.wa && complex_alpha_test && features.feedback_loops())
{
GL_PERF("DATE: Accurate with complex alpha test.");
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
// When Blending is disabled and Edge Anti Aliasing is enabled,
// the output alpha is Coverage (which we force to 128) so DATE will fail/pass guaranteed on second pass.
else if (m_conf.colormask.wa && (m_context->FBA.FBA || IsCoverageAlphaFixedOne()) && features.stencil_buffer)
else if (m_conf.colormask.wa && !complex_alpha_test && (m_context->FBA.FBA || IsCoverageAlphaFixedOne()) && features.stencil_buffer)
{
GL_PERF("DATE: Fast with FBA, all pixels will be >= 128");
date_options.stencil_one = !m_cached_ctx.TEST.DATM;
@@ -6214,7 +6241,7 @@ void GSRendererHW::EmulateDither()
if (m_conf.ps.dither || m_conf.blend_multi_pass.dither)
{
const GIFRegDIMX& DIMX = m_draw_env->DIMX;
GL_DBG("DITHERING mode %d (%d)", (GSConfig.Dithering == 3) ? "Force 32bit" : ((GSConfig.Dithering == 0) ? "Disabled" : "Enabled"), GSConfig.Dithering);
GL_DBG("DITHERING mode %s (%d)", (GSConfig.Dithering == 3) ? "Force 32bit" : ((GSConfig.Dithering == 0) ? "Disabled" : "Enabled"), GSConfig.Dithering);
if (m_conf.ps.dither || GSConfig.Dithering == 3)
m_conf.ps.dither = GSConfig.Dithering;
@@ -7483,34 +7510,34 @@ __fi void GSRendererHW::GetForcedROVUsage(bool& rov_color, bool& rov_depth)
if (rov_color == rov_depth)
return;
// If depth and color have feedback and one uses ROV, the other must also.
// We currently don't have a way of using barriers in one and ROV in the other.
if ((m_conf.ps.IsFeedbackLoopRT() && rov_depth) || (m_conf.ps.IsFeedbackLoopDepth() && rov_color))
// Force color ROV if depth ROV is used.
if (rov_depth)
{
GL_INS("ROV: Depth ROV forces color ROV");
rov_color = true;
return;
}
// If we have a depth feedback loop and color uses ROV, depth must also.
// We currently don't have a way of using barriers in depth and ROV in color.
if (m_conf.ps.IsFeedbackLoopDepth() && rov_color)
{
GL_INS("ROV: Feedback compatibility forces color and depth ROV");
rov_color = true;
rov_depth = true;
return;
}
// If we use color ROV with discard or the pixel shader writes to depth,
// we cannot use early depth stencil, so must use depth ROV with feedback.
// Same applies in reverse for depth ROV forcing color ROV with feedback.
const bool color_write = (m_conf.colormask.wrgba != 0);
const bool depth_test = m_cached_ctx.DepthRead();
// Separate flag for DATE since they are many methods and the interaction with ROV is not clear.
const bool date = m_cached_ctx.TEST.DATE;
if (m_conf.ds && rov_color && (m_conf.ps.HasShaderDiscard() || m_conf.ps.HasDepthOutput() || date))
if (rov_color && (m_conf.ps.HasShaderDiscard() || m_conf.ps.HasDepthOutput() || date))
{
GL_INS("ROV: Color ROV with shader discard/depth write forces depth ROV");
rov_depth = true;
}
else if (m_conf.rt && color_write && rov_depth && (m_conf.ps.HasShaderDiscard() || depth_test || date))
{
GL_INS("ROV: Depth ROV with shader discard forces color ROV");
rov_color = true;
}
}
void GSRendererHW::DetermineROVUsage(GSTextureCache::Target* rt, GSTextureCache::Target* ds)
@@ -7543,45 +7570,29 @@ void GSRendererHW::DetermineROVUsage(GSTextureCache::Target* rt, GSTextureCache:
const bool color_write = rt && m_conf.colormask.wrgba != 0;
const bool depth_write = ds && m_cached_ctx.DepthWrite();
const u32 colormask = GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & m_conf.colormask.wrgba;
const bool colormask_needs_rt = colormask != 0xF;
const u32 ate = m_cached_ctx.TEST.ATE;
const u32 atst = m_cached_ctx.TEST.ATST;
const u32 afail = m_cached_ctx.TEST.AFAIL;
const bool afail_needs_rt = ate && ((afail == AFAIL_ZB_ONLY) || (afail == AFAIL_RGB_ONLY));
const bool afail_needs_depth = ate && ((afail == AFAIL_FB_ONLY) || (afail == AFAIL_RGB_ONLY));
const bool blend = m_conf.IsBlending();
const bool blend_needs_rt = blend &&
(m_optimized_blend.A == ALPHA_ABD_CD || m_optimized_blend.B == ALPHA_ABD_CD ||
m_optimized_blend.C == ALPHA_C_AD || m_optimized_blend.D == ALPHA_ABD_CD);
const bool two_pass_alpha = GSHWDrawConfig::HasAlphaTestSecondPass(m_conf.alpha_test);
const bool date = m_conf.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off;
const bool ztst = m_cached_ctx.DepthRead();
const bool full_barrier = m_conf.require_full_barrier;
bool full_barrier = m_conf.require_full_barrier;
// Heuristically determine what ROVs would be needed to eliminate passes based on the current config.
const bool multipass_color = (full_barrier && m_conf.ps.IsFeedbackLoopRT()) ||
two_pass_alpha ||
m_conf.blend_multi_pass.enable;
bool barriers_color = m_conf.require_full_barrier && m_conf.ps.IsFeedbackLoopRT();
bool barriers_depth = m_conf.require_full_barrier && m_conf.ps.IsFeedbackLoopDepth();
const bool multipass_depth = (full_barrier && m_conf.ps.IsFeedbackLoopDepth()) || two_pass_alpha;
if (m_conf.alpha_second_pass.enable)
{
full_barrier |= m_conf.alpha_second_pass.require_full_barrier;
barriers_color |= m_conf.alpha_second_pass.require_full_barrier && m_conf.alpha_second_pass.ps.IsFeedbackLoopRT();
barriers_depth |= m_conf.alpha_second_pass.require_full_barrier && m_conf.alpha_second_pass.ps.IsFeedbackLoopDepth();
}
// If already ROV, just continue the usage.
const bool color_is_rov = rt && rt->m_texture->IsUnorderedAccess();
const bool depth_is_rov = ds && ds->m_texture->IsDepthColor();
const bool color_is_rov = rt && rt->m_texture->IsShaderWriteMode();
const bool depth_is_rov = ds && ds->m_texture->IsShaderWrite();
bool use_rov_color = (color_write && multipass_color) || color_is_rov;
bool use_rov_depth = (depth_write && multipass_depth) || depth_is_rov;
bool use_rov_color = (color_write && barriers_color) || color_is_rov;
bool use_rov_depth = (depth_write && barriers_depth) || depth_is_rov;
// In certain cases, ROV in color or depth will force ROV in the other for correctness.
GetForcedROVUsage(use_rov_color, use_rov_depth);
if (rt && ds)
GetForcedROVUsage(use_rov_color, use_rov_depth);
// Get the number of barriers that would be used with the current config.
u32 barriers = 1;
@@ -7593,13 +7604,14 @@ void GSRendererHW::DetermineROVUsage(GSTextureCache::Target* rt, GSTextureCache:
}
else
{
#if PCSX2_DEVBUILD
barriers = INT_MAX; // Compute the full drawlist for logging purposes.
#else
barriers = 2; // Tells drawlist computation to stop after reaching 2.
#endif
GetPrimitiveOverlapDrawlist(false, false, 1.0f, &barriers);
}
}
const u32 multiplier = m_conf.alpha_second_pass.enable ? 2 : 1; // Alpha second pass doubles the barriers.
barriers *= multiplier;
// Heuristic: only activate ROV if we save at least one draw call by doing so.
const bool activate = (use_rov_color != color_is_rov || use_rov_depth != depth_is_rov) && barriers >= 2;
@@ -7661,7 +7673,7 @@ void GSRendererHW::ConfigureROV(bool color_rov, bool depth_rov)
{
m_conf.cb_ps.FbMask |= fbmask;
}
GL_INS("ROV: FbMask={ R=%x, G=%x, B=%x, A=%x }",
GL_INS("ROV: FbMask={R=%x, G=%x, B=%x, A=%x}",
m_conf.cb_ps.FbMask.r, m_conf.cb_ps.FbMask.g, m_conf.cb_ps.FbMask.b, m_conf.cb_ps.FbMask.a);
}
else
@@ -7780,89 +7792,92 @@ void GSRendererHW::ConfigureROV(bool color_rov, bool depth_rov)
}
}
void GSRendererHW::SetUnorderedAccessFlag(GSTextureCache::Target* rt)
void GSRendererHW::ConvertTextureTypeROVSingle(GSTextureCache::Target* tgt, bool shader_write)
{
// Set flag for ROV activation heuristic. Only used by DX11.
// Only needed for RT, as we use a different method for depth.
if (rt)
{
if (m_conf.ps.HasColorROV())
rt->m_texture->SetUnorderedAccess();
else
rt->m_texture->ClearUnorderedAccess();
}
}
const bool depth = (tgt->m_type == GSTextureCache::DepthStencil);
static void CopyDepthTextureROV(GSTexture* src, GSTexture* dst)
{
switch (src->GetState())
GSTexture* old_tex = depth ? m_conf.ds : m_conf.rt;
GSTexture::Usage usage = shader_write ? GSTexture::ShaderWriteTarget : GSTexture::FeedbackTarget;
GSTexture* new_tex = depth ?
(shader_write ?
g_gs_device->FetchSurface(usage, old_tex->GetSize(), 1, GSTexture::Format::DepthColor, false, true) :
g_gs_device->CreateDepthStencil(old_tex->GetSize(), false, true)) :
g_gs_device->FetchSurface(usage, old_tex->GetSize(), 1, GSTexture::Format::Color, false, true);
switch (old_tex->GetState())
{
case GSTexture::State::Cleared:
g_gs_device->ClearDepth(dst, src->GetClearDepth());
if (depth)
g_gs_device->ClearDepth(new_tex, old_tex->GetClearDepth());
else
g_gs_device->ClearRenderTarget(new_tex, old_tex->GetClearColor());
break;
case GSTexture::State::Invalidated:
g_gs_device->InvalidateRenderTarget(dst);
g_gs_device->InvalidateRenderTarget(new_tex);
break;
case GSTexture::State::Dirty:
g_gs_device->StretchRectAuto(src, dst, Nearest);
g_gs_device->StretchRectAuto(old_tex, new_tex, Nearest);
// Count stats as part of both standard and ROV.
g_perfmon.Put(GSPerfMon::TextureCopiesROV, 1.0);
g_perfmon.Put(GSPerfMon::DrawCallsROV, 1.0);
break;
default:
pxAssert(false);
break;
}
// These stats are counted both as part of ROV and non-ROV stats.
g_perfmon.Put(GSPerfMon::DepthCopiesROV, 1.0);
g_perfmon.Put(GSPerfMon::DrawCallsROV, 1.0);
};
void GSRendererHW::ConvertDepthFormatROV(GSTextureCache::Target* ds)
{
if (!ds)
return;
GSTexture* ds_tex_old = m_conf.ds;
GSTexture* ds_tex_new = nullptr;
// Convert depth to depth color or vice versa if needed.
bool depth_to_color;
if (m_conf.ps.HasDepthROV() && !ds_tex_old->IsDepthColor())
{
depth_to_color = true;
ds_tex_new = g_gs_device->CreateDepthColor(ds_tex_old->GetSize(), false, true);
}
else if (!m_conf.ps.HasDepthROV() && ds_tex_old->IsDepthColor())
{
depth_to_color = false;
ds_tex_new = g_gs_device->CreateDepthStencil(ds->m_texture->GetSize(), false, true);
}
else
{
return;
}
GL_PUSH("HW: Convert %s for ROV.", depth_to_color ? "DepthStencil -> DepthColor" : "DepthColor -> DepthStencil");
CopyDepthTextureROV(ds_tex_old, ds_tex_new);
#if PCSX2_DEVBUILD
ds_tex_new->SetDebugName(ds->m_texture->GetDebugName());
new_tex->SetDebugName(tgt->m_texture->GetDebugName());
#endif
// Fix up the texture cache.
if (ds->m_texture == ds_tex_old)
if (tgt->m_texture == old_tex)
{
GL_CACHE("HW: Replaced texture for DS @ 0x%04x", ds->m_TEX0.TBP0);
ds->m_texture = ds_tex_new;
GL_CACHE("HW: Replaced texture for %s @ 0x%04x", depth ? "DS" : "RT", tgt->m_TEX0.TBP0);
tgt->m_texture = new_tex;
}
else
{
// Must be the temporary Z.
pxAssert(g_texture_cache->GetTemporaryZ() == ds_tex_old);
pxAssert(depth && g_texture_cache->GetTemporaryZ() == old_tex);
GL_CACHE("HW: Replaced texture for temporary Z @ 0x%04x", g_texture_cache->GetTemporaryZInfo().ZBP);
g_texture_cache->SetTemporaryZ(ds_tex_new);
g_texture_cache->SetTemporaryZ(new_tex);
}
g_gs_device->Recycle(ds_tex_old);
// Fixup the backend config.
if (depth)
m_conf.ds = new_tex;
else
m_conf.rt = new_tex;
m_conf.ds = ds_tex_new;
g_gs_device->Recycle(old_tex);
}
void GSRendererHW::ConvertTextureTypeROV(GSTextureCache::Target* rt, GSTextureCache::Target* ds)
{
// Convert depth to the proper type/format.
if (ds)
{
if (m_conf.ps.HasDepthROV() && !ds->m_texture->IsShaderWrite())
{
GL_PUSH("HW: Convert DepthStencil -> DepthColor for ROV.");
ConvertTextureTypeROVSingle(ds, true);
}
else if (!m_conf.ps.HasDepthROV() && !ds->m_texture->IsDepthStencil())
{
GL_PUSH("HW: Convert DepthColor -> DepthStencil for non-ROV.");
ConvertTextureTypeROVSingle(ds, false);
}
}
// Convert color to the proper type. This only adds the shader read/write flag and doesn't remove it,
// since adding the read/write flag doesn't lose any pipeline capabilities.
if (rt && m_conf.ps.HasColorROV() && !rt->m_texture->IsShaderWrite())
{
GL_PUSH("HW: Convert RenderTarget -> RenderTarget (shader write) for ROV.");
ConvertTextureTypeROVSingle(rt, true);
}
}
__ri static constexpr bool IsRedundantClamp(u8 clamp, u32 clamp_min, u32 clamp_max, u32 tsize)
@@ -9428,8 +9443,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
// Call before computing the full drawlist in case ROV is used and we don't need it.
DetermineROVUsage(rt, ds);
ConvertDepthFormatROV(ds);
SetUnorderedAccessFlag(rt);
ConvertTextureTypeROV(rt, ds);
// Barriers must be determined before indices are modified via HandleProvokingVertexFirst/SetupIA.
// This also computes the drawlist if needed.
@@ -10490,7 +10504,7 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
if (temp_tex)
{
if (GSTexture* rt = g_gs_device->CreateRenderTarget(tw, new_height, GSTexture::Format::Color))
if (GSTexture* rt = g_gs_device->CreateFeedbackTarget(tw, new_height, GSTexture::Format::Color))
{
// sRect is the top of texture
// Need to half pixel offset the dest tex coordinates as draw pixels are top left instead of centre for texel reads.
+2 -2
View File
@@ -256,8 +256,8 @@ private:
void GetForcedROVUsage(bool& color_cov, bool& depth_rov); // Whether having color or depth with the current config forces the other.
void DetermineROVUsage(GSTextureCache::Target* rt, GSTextureCache::Target* ds); // Heuristics to determine whether to enable/disable ROV
void ConfigureROV(bool color_rov, bool depth_rov); // Actual config for ROV
void SetUnorderedAccessFlag(GSTextureCache::Target* rt); // Set flag for DX11 ROV heuristic to work.
void ConvertDepthFormatROV(GSTextureCache::Target* ds); // Convert between depth and depth color if needed.
void ConvertTextureTypeROV(GSTextureCache::Target* rt, GSTextureCache::Target* ds); // Convert to RW capable textures if needed.
void ConvertTextureTypeROVSingle(GSTextureCache::Target* tgt, bool shader_write); // Helper to do the above.
void SetTCOffset();
bool NextDrawColClip() const;
+19 -20
View File
@@ -1757,7 +1757,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
}
else
{
const bool outside_target = !t->Overlaps(bp, bw, psm, r);
const bool outside_target = !t->OverlapsValid(bp, bw, psm, r);
if (!possible_shuffle && outside_target)
{
@@ -4142,7 +4142,7 @@ void GSTextureCache::Target::ScaleRTAlpha()
const GSVector4i valid_rect = GSVector4i(GSVector4(m_valid) * GSVector4(m_scale));
GL_PUSH("TC: ScaleRTAlpha(valid=(%dx%d %d,%d=>%d,%d))", m_valid.width(), m_valid.height(), m_valid.x, m_valid.y, m_valid.z, m_valid.w);
if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize, GSTexture::Format::Color, !GSVector4i::loadh(rtsize).eq(valid_rect)))
if (GSTexture* temp_rt = g_gs_device->CreateCompatible(m_texture, rtsize, !GSVector4i::loadh(rtsize).eq(valid_rect)))
{
// Only copy up the valid area, since there's no point in "correcting" nothing.
const GSVector4 dRect(m_texture->GetRect().rintersect(valid_rect));
@@ -4167,7 +4167,7 @@ void GSTextureCache::Target::UnscaleRTAlpha()
const GSVector4i valid_rect = GSVector4i(GSVector4(m_valid) * GSVector4(m_scale));
GL_PUSH("TC: UnscaleRTAlpha(valid=(%dx%d %d,%d=>%d,%d))", valid_rect.width(), valid_rect.height(), valid_rect.x, valid_rect.y, valid_rect.z, valid_rect.w);
if (GSTexture* temp_rt = g_gs_device->CreateRenderTarget(rtsize, GSTexture::Format::Color, !GSVector4i::loadh(rtsize).eq(valid_rect)))
if (GSTexture* temp_rt = g_gs_device->CreateCompatible(m_texture, rtsize, !GSVector4i::loadh(rtsize).eq(valid_rect)))
{
// Only copy up the valid area, since there's no point in "correcting" nothing.
const GSVector4 dRect(m_texture->GetRect().rintersect(valid_rect));
@@ -4220,7 +4220,7 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
const int new_width = std::max(t->m_unscaled_size.x, needed_width);
const int scaled_new_height = static_cast<int>(std::ceil(static_cast<float>(new_height) * scale));
const int scaled_new_width = static_cast<int>(std::ceil(static_cast<float>(new_width) * scale));
GSTexture* new_texture = g_gs_device->CreateRenderTarget(scaled_new_width, scaled_new_height, GSTexture::Format::Color, false);
GSTexture* new_texture = g_gs_device->CreateCompatible(old_texture, scaled_new_width, scaled_new_height, false);
if (!new_texture)
{
// Memory allocation failure, do our best to hobble along.
@@ -4329,7 +4329,7 @@ bool GSTextureCache::CopyRGBFromDepthToColor(Target* dst, Target* depth_src)
GSTexture* tex = dst->m_texture;
if (needs_new_tex)
{
tex = g_gs_device->CreateRenderTarget(new_scaled_size, GSTexture::Format::Color,
tex = g_gs_device->CreateCompatible(dst->m_texture, new_scaled_size,
new_size != dst->m_unscaled_size || new_size != depth_src->m_unscaled_size);
if (!tex)
return false;
@@ -5296,7 +5296,8 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
req_resize = true;
// If it was matched to an old target, make sure to clear the other type and update its information.
if (dst->m_was_dst_matched)
// Also update information if the buffer width of the new data is larger than the existing target.
if (dst->m_was_dst_matched || (Common::AlignUpPow2(w, 64) / GSLocalMemory::m_psm[new_TEX0.PSM].pgs.x) > dst->m_TEX0.TBW)
{
dst->m_TEX0 = new_TEX0;
}
@@ -6067,10 +6068,9 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
// If we have a source larger than the target, we need to clear it, otherwise we'll read junk
const bool outside_target = ((x + w) > dst->m_texture->GetWidth() || (y + h) > dst->m_texture->GetHeight());
GSTexture::Usage usage = outside_target ? dst->m_texture->GetUsage() : GSTexture::Texture;
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = outside_target ?
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) :
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture());
GSTexture* dTex = g_gs_device->FetchSurface(usage, w, h, outside_target ? 1 : tlevels, sTex->GetFormat(), true, PreferReusedLabelledTexture());
if (!dTex) [[unlikely]]
{
Console.Error("Failed to allocate %dx%d texture for offset source", w, h);
@@ -6378,10 +6378,9 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
// Don't be fooled by the name. 'dst' is the old target (hence the input)
// 'src' is the new texture cache entry (hence the output)
GSTexture::Usage usage = use_texture ? GSTexture::Texture : dst->m_texture->GetUsage();
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = use_texture ?
g_gs_device->CreateTexture(new_size, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(new_size, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
GSTexture* dTex = g_gs_device->FetchSurface(usage, new_size, 1, sTex->GetFormat(), source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
if (!dTex) [[unlikely]]
{
Console.Error("Failed to allocate %dx%d texture for target copy to source", new_size.x, new_size.y);
@@ -6426,9 +6425,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
const u32 destination_tbw = (dst->m_TEX0.TBP0 == TEX0.TBP0) ? (std::max<u32>(TEX0.TBW, 1u) * 64) : std::max<u32>(dst->m_TEX0.TBW, 1u) * 128;
if (!GSConfig.UserHacks_NativePaletteDraw && dst->GetScale() > 1.0f)
{
GSTexture* tmpTex = use_texture ?
g_gs_device->CreateTexture(dst->m_unscaled_size, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(dst->m_unscaled_size, GSTexture::Format::Color, false, PreferReusedLabelledTexture());
GSTexture::Usage usage = use_texture ? GSTexture::Texture : dst->m_texture->GetUsage();
GSTexture* tmpTex = g_gs_device->FetchSurface(usage, dst->m_unscaled_size, 1, dst->m_texture->GetFormat(), false, PreferReusedLabelledTexture());
const GSVector4 dRect = GSVector4(GSVector4i::loadh(dst->m_unscaled_size));
@@ -6909,7 +6907,7 @@ GSTextureCache::Source* GSTextureCache::CreateMergedSource(GIFRegTEX0 TEX0, GIFR
lmtex->Unmap();
// Allocate our render target for drawing everything to.
GSTexture* dtex = g_gs_device->CreateRenderTarget(scaled_width, scaled_height, GSTexture::Format::Color, true);
GSTexture* dtex = g_gs_device->CreateFeedbackTarget(scaled_width, scaled_height, GSTexture::Format::Color, true);
if (!dtex) [[unlikely]]
{
Console.Error("Failed to allocate %dx%d merged dest texture", scaled_width, scaled_height);
@@ -7167,9 +7165,10 @@ GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, i
const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale));
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale));
GSTexture* texture = (type == RenderTarget) ?
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) :
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, clear, PreferReusedLabelledTexture());
GSTexture::Usage usage = type == RenderTarget ? GSTexture::FeedbackTarget :
(g_gs_device->Features().depth_feedback ? GSTexture::FeedbackDepth : GSTexture::DepthStencil);
GSTexture::Format format = type == RenderTarget ? GSTexture::Format::Color : GSTexture::Format::DepthStencil;
GSTexture* texture = g_gs_device->FetchSurface(usage, scaled_w, scaled_h, 1, format, clear, PreferReusedLabelledTexture());
if (!texture)
return nullptr;
@@ -7836,7 +7835,7 @@ GSTextureCache::Target::~Target()
bool GSTextureCache::Target::OverlapsValid(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const
{
const u32 valid_start_block = GSLocalMemory::m_psm[m_TEX0.PSM].info.bn(m_valid.x, m_valid.y, m_TEX0.TBP0, m_TEX0.TBW);
const u32 valid_start_block = GSLocalMemory::GetStartBlockAddress(m_TEX0.TBP0, m_TEX0.TBW, m_TEX0.PSM, m_valid);
return OverlapsHelper(valid_start_block, UnwrappedEndBlock(), bp, bw, psm, rect);
}
+4 -1
View File
@@ -377,7 +377,7 @@ public:
/// Call at the end of each frame
void FrameCompleted();
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) override;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
@@ -414,6 +414,9 @@ public:
float GetAndResetAccumulatedGPUTime() override;
void AccumulateCommandBufferTime(id<MTLCommandBuffer> buffer);
bool SetGPUPipelineStatisticsEnabled(bool enabled) override { return false; }
GPUPipelineStatistics GetAndResetAccumulatedGPUPipelineStatistics() override { return {}; }
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
void ClearSamplerCache() override;
+30 -28
View File
@@ -545,8 +545,10 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
}
}
GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
{ @autoreleasepool {
pxAssert(GSTexture::ValidateUsageAndFormat(usage, format));
MTLPixelFormat fmt = ConvertPixelFormat(format);
pxAssertRel(format != GSTexture::Format::Invalid, "Can't create surface of this format!");
@@ -560,38 +562,38 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
[desc setMipmapLevelCount:levels];
[desc setStorageMode:MTLStorageModePrivate];
switch (type)
MTLTextureUsage mtl_usage = MTLTextureUsageShaderRead;
if (GSTexture::IsRenderTarget(usage))
{
case GSTexture::Type::Texture:
[desc setUsage:MTLTextureUsageShaderRead];
break;
case GSTexture::Type::RenderTarget:
if (m_dev.features.slow_color_compression)
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsagePixelFormatView]; // Force color compression off by including PixelFormatView
else
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget];
break;
case GSTexture::Type::RWTexture:
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite];
break;
default:
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget];
mtl_usage |= MTLTextureUsageRenderTarget;
}
if ((usage & GSTexture::FeedbackTarget) == GSTexture::FeedbackTarget)
{
if (m_dev.features.slow_color_compression)
mtl_usage |= MTLTextureUsagePixelFormatView; // Force color compression off by including PixelFormatView
}
if (GSTexture::IsShaderWrite(usage))
{
mtl_usage |= MTLTextureUsageShaderWrite;
}
[desc setUsage:mtl_usage];
MRCOwned<id<MTLTexture>> tex = MRCTransfer([m_dev.dev newTextureWithDescriptor:desc]);
if (tex)
{
GSTextureMTL* t = new GSTextureMTL(this, tex, type, format);
switch (type)
GSTextureMTL* t = new GSTextureMTL(this, tex, usage, format);
if (GSTexture::IsRenderTarget(usage))
{
case GSTexture::Type::RenderTarget:
ClearRenderTarget(t, 0);
break;
case GSTexture::Type::DepthStencil:
ClearDepth(t, 0.0f);
break;
default:
break;
ClearRenderTarget(t, 0);
}
else if (GSTexture::IsDepthStencil(usage))
{
ClearDepth(t, 0.0f);
}
return t;
}
@@ -2005,7 +2007,7 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
MTLRenderPipelineColorAttachmentDescriptor* color1 = [[pdesc colorAttachments] objectAtIndexedSubscript:1];
[color1 setPixelFormat:MTLPixelFormatR32Float];
}
NSString* pname = [NSString stringWithFormat:@"HW Render %x.%x.%llx.%llx", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey];
NSString* pname = [NSString stringWithFormat:@"HW Render %x.%llx.%llx.%x", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey];
auto pipeline = MakePipeline(pdesc, vs, ps, pname);
[m_current_render.encoder setRenderPipelineState:pipeline];
@@ -2290,7 +2292,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
config.colclip_update_area = config.drawarea;
GSVector2i size = config.rt->GetSize();
rt = colclip_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::ColorClip, false);
rt = colclip_rt = CreateFeedbackTarget(size.x, size.y, GSTexture::Format::ColorClip, false);
g_gs_device->SetColorClipTexture(colclip_rt);
+6 -1
View File
@@ -98,7 +98,7 @@ struct GSMTLMainVSUniform
vector_float2 texture_offset;
vector_float2 point_size;
uint max_depth;
uint _pad0;
float line_aa1_width;
};
struct GSMTLMainPSUniform
@@ -140,6 +140,11 @@ struct GSMTLMainPSUniform
matrix_float4x4 dither_matrix;
vector_float4 scale_factor;
float line_cov_scale;
float _pad0;
float _pad1;
float _pad2;
};
enum GSMTLAttributes
+1 -1
View File
@@ -26,7 +26,7 @@ class GSTextureMTL : public GSTexture
public:
u64 m_last_read = 0; ///< Last time this texture was read by a draw
u64 m_last_write = 0; ///< Last time this texture was written by a draw
GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Type type, Format format);
GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Usage usage, Format format);
~GSTextureMTL();
/// For making fake backbuffers
+4 -2
View File
@@ -13,11 +13,11 @@
// Uploads/downloads need 32-byte alignment for AVX2.
static constexpr u32 PITCH_ALIGNMENT = 32;
GSTextureMTL::GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Type type, Format format)
GSTextureMTL::GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Usage usage, Format format)
: m_dev(dev)
, m_texture(std::move(texture))
{
m_type = type;
m_usage = usage;
m_format = format;
m_size.x = [m_texture width];
m_size.y = [m_texture height];
@@ -142,6 +142,8 @@ void GSTextureMTL::SetDebugName(std::string_view name)
encoding:NSUTF8StringEncoding];
[m_texture setLabel:label];
}
m_debug_name = std::move(name);
}
#endif
+46 -51
View File
@@ -398,16 +398,11 @@ vertex MainVSOut vs_main_expand(
// Use bottom minus top for delta regardless of which vertex we are expanding.
float2 line_delta = is_bottom ? point.p.xy - other.p.xy : other.p.xy - point.p.xy;
float2 line_vector = normalize(line_delta / cb.vertex_scale);
float2 line_expand;
if (VS_EXPAND_TYPE == VSExpand::Line)
{
line_expand = float2(line_vector.y, -line_vector.x);
}
else
{
// Expand in y direction for shallow lines and x direction for steep lines.
line_expand = abs(line_vector.x) >= abs(line_vector.y) ? float2(0, 2) : float2(2, 0);
}
float2 line_expand = float2(line_vector.y, -line_vector.x);
if (VS_EXPAND_TYPE == VSExpand::LineAA1)
line_expand *= 2.f * cb.line_aa1_width;
float2 line_width = (line_expand * cb.point_size) / 2;
float2 offset = is_right ? line_width : -line_width;
point.p.xy += offset;
@@ -616,22 +611,27 @@ struct PSMain
float4 sample_c_af(float2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = any(isnan(uv) | isinf(uv)) ? float2(0, 0) : uv;
uv = any(isnan(uv) | isinf(uv)) ? float2(0.0f, 0.0f) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// And https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_filter_anisotropic.txt
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
float2 sz = float2(get_tex_dims());
float2 dX = dfdx(uv) * sz;
float2 dY = dfdy(uv) * sz;
float length_x = length(dX);
float length_y = length(dY);
// Calculate Ellipse Transform
bool d_zero = length(dX) == 0 || length(dY) == 0;
bool d_par = (dX.x * dY.y - dY.x * dX.y) == 0;
bool d_per = dot(dX, dY) == 0;
bool d_zero = length_x < 0.001f || length_y < 0.001f;
float f = (dX.x * dY.y - dX.y * dY.x);
bool d_par = f < 0.001f;
bool d_per = dot(dX, dY) < 0.001f;
bool d_inf_nan = any(isinf(dX) | isinf(dY) | isnan(dX) | isnan(dY));
if (!(d_zero || d_par || d_per || d_inf_nan))
@@ -639,21 +639,30 @@ struct PSMain
float A = dX.y * dX.y + dY.y * dY.y;
float B = -2 * (dX.x * dX.y + dY.x * dY.y);
float C = dX.x * dX.x + dY.x * dY.x;
float f = (dX.x * dY.y - dY.x * dX.y);
float F = f * f;
float p = A - C;
float q = A + C;
float t = sqrt(p * p + B * B);
float signB = sign(B);
float denom_plus = t * (q + t);
float denom_minus = t * (q - t);
float sqrtA = sqrt(F * (t + p));
float sqrtB = sqrt(F * (t - p));
float inv_sqrt_denom_plus = rsqrt(denom_plus);
float inv_sqrt_denom_minus = rsqrt(denom_minus);
float2 new_dX = float2(
sqrt(F * (t + p) / (t * (q + t))),
sqrt(F * (t - p) / (t * (q + t))) * sign(B)
sqrtA * inv_sqrt_denom_plus,
sqrtB * inv_sqrt_denom_plus * signB
);
float2 new_dY = float2(
sqrt(F * (t - p) / (t * (q - t))) * -sign(B),
sqrt(F * (t + p) / (t * (q - t)))
sqrtB * inv_sqrt_denom_minus * -signB,
sqrtA * inv_sqrt_denom_minus
);
d_inf_nan = any(isinf(new_dX) | isinf(new_dY) | isnan(new_dX) | isnan(new_dY));
@@ -661,16 +670,15 @@ struct PSMain
{
dX = new_dX;
dY = new_dY;
length_x = length(dX);
length_y = length(dY);
}
}
// Compute AF values
float squared_length_x = dX.x * dX.x + dX.y * dX.y;
float squared_length_y = dY.x * dY.x + dY.y * dY.y;
float determinant = abs(dX.x * dY.y - dX.y * dY.x);
bool is_major_x = squared_length_x > squared_length_y;
float squared_length_major = is_major_x ? squared_length_x : squared_length_y;
float length_major = sqrt(squared_length_major);
bool is_major_x = length_x > length_y;
float length_major = is_major_x ? length_x : length_y;
float length_minor = is_major_x ? length_y : length_x;
float aniso_ratio;
float length_lod;
@@ -682,41 +690,25 @@ struct PSMain
// Perform isotropic filtering instead.
aniso_ratio = 1.0f;
length_lod = length_major;
aniso_line = float2(0, 0);
aniso_line = float2(0.0f, 0.0f);
}
else
{
float norm_major = 1.0f / length_major;
float2 aniso_line_dir = is_major_x ? dX : dY;
float2 aniso_line_dir = float2(
(is_major_x ? dX.x : dY.x) * norm_major,
(is_major_x ? dX.y : dY.y) * norm_major
);
aniso_ratio = squared_length_major / determinant;
// Calculate the minor length of the ellipse for Lod, while also clamping the ratio of anisotropy.
if (aniso_ratio > PS_SW_ANISO)
{
// ratio is clamped - Lod is based on ratio (preserves area)
aniso_ratio = PS_SW_ANISO;
length_lod = length_major / PS_SW_ANISO;
}
else
{
// ratio not clamped - Lod is based on area
length_lod = determinant / length_major;
}
aniso_ratio = min(length_major / length_minor, float(PS_SW_ANISO));
length_lod = length_major / aniso_ratio;
// clamp to top Lod
if (length_lod < 1.0f)
aniso_ratio = max(1.0f, aniso_ratio * length_lod);
aniso_ratio = round(aniso_ratio);
aniso_line = aniso_line_dir * 0.5f * length_major * (1.0f / sz);
aniso_line = aniso_line_dir * 0.5f * (1.0f / sz);
}
float lod = PS_AUTOMATIC_LOD ? log2(length_lod) : PS_MANUAL_LOD ? manual_lod(uv_w) : 0;
float lod = PS_AUTOMATIC_LOD ? log2(length_lod) : PS_MANUAL_LOD ? manual_lod(uv_w) : 0.0f;
float4 colour;
if (aniso_ratio == 1.0f)
@@ -725,10 +717,11 @@ struct PSMain
}
else
{
float4 num = float4(0, 0, 0, 0);
float4 num = float4(0.0f, 0.0f, 0.0f, 0.0f);
float2 segment = (2.0f * aniso_line) / aniso_ratio;
for (int i = 0; i < aniso_ratio; i++)
{
float2 d = -aniso_line + (0.5f + i) * (2.0f * aniso_line) / aniso_ratio;
float2 d = -aniso_line + (0.5f + i) * segment;
float2 uv_sample = uv + d;
float4 sample_colour = sample_tex(tex_sampler, uv_sample, level(lod));
num += sample_colour;
@@ -1507,7 +1500,9 @@ struct PSMain
if (PS_AA1 != AA1::NONE)
{
float cov = saturate(1.f - abs(in.inv_cov));
float cov = PS_AA1 == AA1::LINE ?
saturate(cb.line_cov_scale * (1.f - abs(in.inv_cov))) : // Blur only outer part of the line by scaling coverage.
saturate(1.f - abs(in.inv_cov));
if (!PS_ABE || floor(C.a) == 128.f) // The coverage is only used if the fragment alpha is 128.
C.a = 128.f * cov;
}
+113 -13
View File
@@ -213,10 +213,11 @@ std::vector<GSAdapterInfo> GSDeviceOGL::GetAdapterInfo()
return ret;
}
GSTexture* GSDeviceOGL::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
GSTexture* GSDeviceOGL::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
{
GL_PUSH("Create surface");
return new GSTextureOGL(type, width, height, levels, format);
pxAssert(GLAD_GL_ARB_shader_image_load_store || !GSTexture::IsShaderWrite(usage));
return new GSTextureOGL(usage, width, height, levels, format);
}
RenderAPI GSDeviceOGL::GetRenderAPI() const
@@ -656,6 +657,8 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
if (!CreateImGuiProgram())
return false;
m_gpu_pipeline_statistics_supported = (GLAD_GL_ARB_pipeline_statistics_query != 0);
// Basic to ensure structures are correctly packed
static_assert(sizeof(VSSelector) == 1, "Wrong VSSelector size");
static_assert(sizeof(PSSelector) == 16, "Wrong PSSelector size");
@@ -673,6 +676,7 @@ void GSDeviceOGL::Destroy()
if (m_gl_context)
{
DestroyTimestampQueries();
DestroyPipelineStatisticsQueries();
DestroyResources();
m_gl_context->DoneCurrent();
@@ -907,11 +911,6 @@ bool GSDeviceOGL::CheckFeatures()
}
m_features.aa1 = GSConfig.HWAA1 && m_features.vs_expand && m_features.feedback_loops();
if (GSConfig.HWROV)
{
Console.Warning("GL: ROV is not implemented for GL and will be disabled.");
}
return true;
}
@@ -1088,6 +1087,10 @@ GSDevice::PresentResult GSDeviceOGL::BeginPresent(bool frame_skip)
if (frame_skip || m_window_info.type == WindowInfo::Type::Surfaceless)
return PresentResult::FrameSkipped;
// Get the pipeline statistics for this frame before postprocessing.
if (m_gpu_pipeline_statistics_enabled)
PopPipelineStatisticsQuery();
OMSetFBO(0);
OMSetColorMaskState();
@@ -1114,6 +1117,9 @@ void GSDeviceOGL::EndPresent()
if (m_gpu_timing_enabled)
KickTimestampQuery();
if (m_gpu_pipeline_statistics_enabled)
KickPipelineStatisticsQuery();
}
void GSDeviceOGL::CreateTimestampQueries()
@@ -1195,6 +1201,100 @@ float GSDeviceOGL::GetAndResetAccumulatedGPUTime()
return value;
}
void GSDeviceOGL::PopPipelineStatisticsQuery()
{
while (m_waiting_pipeline_statistics_queries > 0)
{
GLint available[2] = {};
glGetQueryObjectiv(m_pipeline_statistics_queries[m_read_pipeline_statistics_query][0], GL_QUERY_RESULT_AVAILABLE, &available[0]);
glGetQueryObjectiv(m_pipeline_statistics_queries[m_read_pipeline_statistics_query][1], GL_QUERY_RESULT_AVAILABLE, &available[1]);
if (!(available[0] && available[1]))
break;
GPUPipelineStatistics stats = {};
glGetQueryObjectui64v(m_pipeline_statistics_queries[m_read_pipeline_statistics_query][0], GL_QUERY_RESULT, &stats.vs_invocations);
glGetQueryObjectui64v(m_pipeline_statistics_queries[m_read_pipeline_statistics_query][1], GL_QUERY_RESULT, &stats.ps_invocations);
m_accumulated_gpu_pipeline_statistics.vs_invocations += stats.vs_invocations;
m_accumulated_gpu_pipeline_statistics.ps_invocations += stats.ps_invocations;
m_read_pipeline_statistics_query = (m_read_pipeline_statistics_query + 1) % NUM_PIPELINE_STATISTICS_QUERIES;
m_waiting_pipeline_statistics_queries--;
}
if (m_pipeline_statistics_query_started)
{
glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB);
glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB);
m_write_pipeline_statistics_query = (m_write_pipeline_statistics_query + 1) % NUM_TIMESTAMP_QUERIES;
m_pipeline_statistics_query_started = false;
m_waiting_pipeline_statistics_queries++;
}
}
void GSDeviceOGL::KickPipelineStatisticsQuery()
{
if (m_pipeline_statistics_query_started || m_waiting_pipeline_statistics_queries == NUM_PIPELINE_STATISTICS_QUERIES)
return;
glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, m_pipeline_statistics_queries[m_write_pipeline_statistics_query][0]);
glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, m_pipeline_statistics_queries[m_write_pipeline_statistics_query][1]);
m_pipeline_statistics_query_started = true;
}
void GSDeviceOGL::CreatePipelineStatisticsQueries()
{
for (int i = 0; i < NUM_PIPELINE_STATISTICS_QUERIES; i++)
{
glGenQueries(2, m_pipeline_statistics_queries[i].data());
}
KickPipelineStatisticsQuery();
}
void GSDeviceOGL::DestroyPipelineStatisticsQueries()
{
if (m_pipeline_statistics_queries[0][0] == 0)
return;
if (m_pipeline_statistics_query_started)
{
glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB);
glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB);
}
for (int i = 0; i < m_pipeline_statistics_queries.size(); i++)
{
glDeleteQueries(2, m_pipeline_statistics_queries[i].data());
m_pipeline_statistics_queries[i].fill(0);
}
m_read_pipeline_statistics_query = 0;
m_write_pipeline_statistics_query = 0;
m_waiting_pipeline_statistics_queries = 0;
m_pipeline_statistics_query_started = false;
}
GPUPipelineStatistics GSDeviceOGL::GetAndResetAccumulatedGPUPipelineStatistics()
{
GPUPipelineStatistics stats = m_accumulated_gpu_pipeline_statistics;
m_accumulated_gpu_pipeline_statistics = {};
return stats;
}
bool GSDeviceOGL::SetGPUPipelineStatisticsEnabled(bool enabled)
{
if (m_gpu_pipeline_statistics_enabled == enabled)
return true;
m_gpu_pipeline_statistics_enabled = enabled && m_gpu_pipeline_statistics_supported;
if (m_gpu_pipeline_statistics_enabled)
CreatePipelineStatisticsQueries();
else
DestroyPipelineStatisticsQueries();
return true;
}
void GSDeviceOGL::DrawPrimitive()
{
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
@@ -1259,14 +1359,14 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_write);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
(t->GetType() == GSTexture::Type::RenderTarget) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
t->IsRenderTarget() ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, (t->GetType() == GSTexture::Type::DepthStencil) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
GL_TEXTURE_2D, t->IsDepthStencil() ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
}
else
{
OMSetFBO(m_fbo);
if (T->GetType() == GSTexture::Type::DepthStencil)
if (T->IsDepthStencil())
{
if (GLState::rt && GLState::rt->GetSize() != T->GetSize())
OMAttachRt(nullptr);
@@ -1284,7 +1384,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
{
if (GLAD_GL_VERSION_4_3)
{
if (T->GetType() == GSTexture::Type::DepthStencil)
if (T->IsDepthStencil())
{
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
@@ -1344,7 +1444,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
if (use_write_fbo)
{
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
(t->GetType() == GSTexture::Type::RenderTarget) ?
t->IsRenderTarget() ?
GL_COLOR_ATTACHMENT0 :
(m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT),
GL_TEXTURE_2D, 0, 0);
@@ -2792,7 +2892,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
{
config.colclip_update_area = config.drawarea;
colclip_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false);
colclip_rt = CreateFeedbackTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false);
if (!colclip_rt)
{
+19 -1
View File
@@ -147,6 +147,7 @@ public:
private:
static constexpr u8 NUM_TIMESTAMP_QUERIES = 5;
static constexpr u8 NUM_PIPELINE_STATISTICS_QUERIES = 5;
std::unique_ptr<GLContext> m_gl_context;
@@ -253,6 +254,15 @@ private:
bool m_timestamp_query_started = false;
bool m_gpu_timing_enabled = false;
std::array<std::array<GLuint, 2>, NUM_PIPELINE_STATISTICS_QUERIES> m_pipeline_statistics_queries = {};
GPUPipelineStatistics m_accumulated_gpu_pipeline_statistics = {};
u8 m_read_pipeline_statistics_query = 0;
u8 m_write_pipeline_statistics_query = 0;
u8 m_waiting_pipeline_statistics_queries = 0;
bool m_pipeline_statistics_query_started = false;
bool m_gpu_pipeline_statistics_enabled = false;
bool m_gpu_pipeline_statistics_supported = false;
GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache;
GSHWDrawConfig::PSConstantBuffer m_ps_cb_cache;
GSHWDrawConfig::VSPushConstants m_vs_pc_cache;
@@ -270,7 +280,12 @@ private:
void PopTimestampQuery();
void KickTimestampQuery();
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) override;
void CreatePipelineStatisticsQueries();
void DestroyPipelineStatisticsQueries();
void PopPipelineStatisticsQuery();
void KickPipelineStatisticsQuery();
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) override;
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
@@ -337,6 +352,9 @@ public:
bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
bool SetGPUPipelineStatisticsEnabled(bool enabled) override;
GPUPipelineStatistics GetAndResetAccumulatedGPUPipelineStatistics() override;
// Helpers and utility draws.
void DrawPrimitive();
void DrawIndexedPrimitive();
+6 -6
View File
@@ -21,13 +21,13 @@ static constexpr u32 TEXTURE_UPLOAD_ALIGNMENT = 64;
// We need 32 here for AVX2, so 64 is also fine.
static constexpr u32 TEXTURE_UPLOAD_PITCH_ALIGNMENT = 64;
GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format format)
GSTextureOGL::GSTextureOGL(Usage usage, int width, int height, int levels, Format format)
{
// OpenGL didn't like dimensions of size 0
m_size.x = std::max(1, width);
m_size.y = std::max(1, height);
m_usage = usage;
m_format = format;
m_type = type;
m_texture_id = 0;
m_mipmap_levels = 1;
@@ -144,7 +144,7 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
}
// Only 32 bits input texture will be supported for mipmap
if (m_type == Type::Texture)
if (IsTexture())
m_mipmap_levels = levels;
// Create a gl object (texture isn't allocated here)
@@ -181,7 +181,7 @@ void* GSTextureOGL::GetNativeHandle() const
bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int layer)
{
pxAssert(m_type != Type::DepthStencil);
pxAssert(!IsDepthStencil());
if (layer >= m_mipmap_levels)
return true;
@@ -263,7 +263,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
const u32 pitch = Common::AlignUpPow2(r.width() << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
m.pitch = pitch;
if (m_type == Type::Texture || m_type == Type::RenderTarget)
if (IsTexture() || IsRenderTarget())
{
const u32 upload_size = CalcUploadSize(r.height(), pitch);
GLStreamBuffer* sb = GSDeviceOGL::GetInstance()->GetTextureUploadBuffer();
@@ -292,7 +292,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
void GSTextureOGL::Unmap()
{
if (m_type == Type::Texture || m_type == Type::RenderTarget)
if (IsTexture() || IsRenderTarget())
{
GSDeviceOGL::GetInstance()->CommitClear(this, true);
+1 -1
View File
@@ -28,7 +28,7 @@ private:
u32 m_int_shift = 0;
public:
explicit GSTextureOGL(Type type, int width, int height, int levels, Format format);
explicit GSTextureOGL(Usage usage, int width, int height, int levels, Format format);
~GSTextureOGL() override;
__fi GLenum GetIntFormat() const { return m_int_format; }
+108 -23
View File
@@ -462,6 +462,7 @@ bool GSDeviceVK::SelectDeviceFeatures()
m_device_features.textureCompressionBC = available_features.textureCompressionBC;
m_device_features.geometryShader = available_features.geometryShader;
m_device_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics;
m_device_features.pipelineStatisticsQuery = available_features.pipelineStatisticsQuery;
return true;
}
@@ -697,6 +698,9 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
queue_family_properties[m_graphics_queue_family_index].timestampValidBits,
m_device_properties.limits.timestampPeriod);
m_gpu_pipeline_statistics_supported = (m_device_features.pipelineStatisticsQuery != 0);
DevCon.WriteLn("GPU pipeline statistics is %s", m_gpu_pipeline_statistics_supported ? "supported" : "not supported");
if (!ProcessDeviceExtensions())
return false;
@@ -997,6 +1001,20 @@ bool GSDeviceVK::CreateGlobalDescriptorPool()
}
}
if (m_gpu_pipeline_statistics_supported)
{
const VkQueryPoolCreateInfo query_create_info = {
VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr, 0, VK_QUERY_TYPE_PIPELINE_STATISTICS, NUM_COMMAND_BUFFERS,
VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT };
res = vkCreateQueryPool(m_device, &query_create_info, nullptr, &m_pipeline_statistics_query_pool);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateQueryPool failed: ");
m_gpu_pipeline_statistics_supported = false;
return false;
}
}
return true;
}
@@ -1122,6 +1140,19 @@ bool GSDeviceVK::SetGPUTimingEnabled(bool enabled)
return (enabled == m_gpu_timing_enabled);
}
GPUPipelineStatistics GSDeviceVK::GetAndResetAccumulatedGPUPipelineStatistics()
{
GPUPipelineStatistics stats = m_accumulated_gpu_pipeline_statistics;
m_accumulated_gpu_pipeline_statistics = {};
return stats;
}
bool GSDeviceVK::SetGPUPipelineStatisticsEnabled(bool enabled)
{
m_gpu_pipeline_statistics_enabled = enabled && m_gpu_pipeline_statistics_supported;
return true;
}
void GSDeviceVK::ScanForCommandBufferCompletion()
{
for (u32 check_index = (m_current_frame + 1) % NUM_COMMAND_BUFFERS; check_index != m_current_frame;
@@ -1198,6 +1229,13 @@ void GSDeviceVK::SubmitCommandBuffer(VKSwapChain* present_swap_chain)
m_current_frame * 2 + 1);
}
if (resources.pipeline_statistics_query == QueryState::Querying)
{
// Didn't end query in BeginPresent() so end it here.
resources.pipeline_statistics_query = QueryState::Ready;
vkCmdEndQuery(m_current_command_buffer, m_pipeline_statistics_query_pool, m_current_frame);
}
res = vkEndCommandBuffer(resources.command_buffers[1]);
if (res != VK_SUCCESS)
{
@@ -1404,6 +1442,33 @@ void GSDeviceVK::ActivateCommandBuffer(u32 index)
resources.command_buffers[1], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, m_timestamp_query_pool, index * 2);
}
if (resources.pipeline_statistics_query == QueryState::Ready)
{
// Collect the pipeline statistics from the last time this cmdbuffer was used.
resources.pipeline_statistics_query = QueryState::None;
GPUPipelineStatistics stats{};
VkResult res =
vkGetQueryPoolResults(m_device, m_pipeline_statistics_query_pool, index, 1,
sizeof(stats), &stats, sizeof(u64), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
if (res == VK_SUCCESS)
{
m_accumulated_gpu_pipeline_statistics.vs_invocations += stats.vs_invocations;
m_accumulated_gpu_pipeline_statistics.ps_invocations += stats.ps_invocations;
}
else
{
LOG_VULKAN_ERROR(res, "vkGetQueryPoolResults failed: ");
}
}
if (m_gpu_pipeline_statistics_enabled)
{
pxAssert(resources.pipeline_statistics_query == QueryState::None);
resources.pipeline_statistics_query = QueryState::Querying;
vkCmdResetQueryPool(resources.command_buffers[1], m_pipeline_statistics_query_pool, index, 1);
vkCmdBeginQuery(resources.command_buffers[1], m_pipeline_statistics_query_pool, index, 0);
}
resources.fence_counter = m_next_fence_counter++;
resources.init_buffer_used = false;
resources.timestamp_written = wants_timestamp;
@@ -2119,7 +2184,7 @@ bool GSDeviceVK::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
return false;
}
if ((m_null_framebuffer = GSTextureVK::CreateNullFramebuffer()) == VK_NULL_HANDLE)
if ((m_null_framebuffer = GSTextureVK::CreateNullFramebuffer(m_max_framebuffer_width, m_max_framebuffer_height)) == VK_NULL_HANDLE)
{
Host::ReportErrorAsync("GS", "Failed to create dummy framebuffer");
return false;
@@ -2367,6 +2432,14 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip)
return PresentResult::FrameSkipped;
}
// End the pipeline statistics for this cmdbuffer before postprocessing.
FrameResources& resources = m_frame_resources[m_current_frame];
if (resources.pipeline_statistics_query == QueryState::Querying)
{
resources.pipeline_statistics_query = QueryState::Ready;
vkCmdEndQuery(m_current_command_buffer, m_pipeline_statistics_query_pool, m_current_frame);
}
VkResult res = m_resize_requested ? VK_ERROR_OUT_OF_DATE_KHR : m_swap_chain->AcquireNextImage();
if (res != VK_SUCCESS)
{
@@ -2735,14 +2808,18 @@ bool GSDeviceVK::CheckFeatures()
m_features.point_expand ? "hardware" : "vertex expanding",
m_features.line_expand ? "hardware" : "vertex expanding");
bool has_rov_storage_flags = true;
// Check texture format support before we try to create them.
for (u32 fmt = static_cast<u32>(GSTexture::Format::Color); fmt < static_cast<u32>(GSTexture::Format::PrimID); fmt++)
{
const VkFormat vkfmt = LookupNativeFormat(static_cast<GSTexture::Format>(fmt));
const VkFormatFeatureFlags bits =
(static_cast<GSTexture::Format>(fmt) == GSTexture::Format::DepthStencil) ?
(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) :
(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
VkFormatFeatureFlags bits = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
if (static_cast<GSTexture::Format>(fmt) == GSTexture::Format::DepthStencil)
bits |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
else
bits |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
VkFormatProperties props = {};
vkGetPhysicalDeviceFormatProperties(m_physical_device, vkfmt, &props);
@@ -2753,6 +2830,9 @@ bool GSDeviceVK::CheckFeatures()
fmt, static_cast<unsigned>(vkfmt), props.optimalTilingFeatures, bits);
return false;
}
if (GSTexture::IsShaderWriteFormat(static_cast<GSTexture::Format>(fmt)))
has_rov_storage_flags &= ((props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0);
}
m_features.dxt_textures = m_device_features.textureCompressionBC;
@@ -2767,9 +2847,13 @@ bool GSDeviceVK::CheckFeatures()
}
m_max_texture_size = m_device_properties.limits.maxImageDimension2D;
m_max_framebuffer_width = m_device_properties.limits.maxFramebufferWidth;
m_max_framebuffer_height = m_device_properties.limits.maxFramebufferHeight;
m_features.rov = m_optional_extensions.vk_ext_fragment_shader_interlock &&
m_device_features.fragmentStoresAndAtomics;
m_device_features.fragmentStoresAndAtomics &&
has_rov_storage_flags &&
!m_features.framebuffer_fetch;
return true;
}
@@ -2853,15 +2937,15 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
VK_FORMAT_D32_SFLOAT;
}
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
{
std::unique_ptr<GSTexture> tex = GSTextureVK::Create(type, format, width, height, levels);
std::unique_ptr<GSTexture> tex = GSTextureVK::Create(usage, format, width, height, levels);
if (!tex)
{
// We're probably out of vram, try flushing the command buffer to release pending textures.
PurgePool();
ExecuteCommandBufferAndRestartRenderPass(true, "Couldn't allocate texture.");
tex = GSTextureVK::Create(type, format, width, height, levels);
tex = GSTextureVK::Create(usage, format, width, height, levels);
}
return tex.release();
@@ -2895,7 +2979,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
return;
// Do an attachment clear.
const bool depth = (dTexVK->GetType() == GSTexture::Type::DepthStencil);
const bool depth = dTexVK->IsDepthStencil();
OMSetRenderTargets(depth ? nullptr : dTexVK, depth ? dTexVK : nullptr, dst_rect);
BeginRenderPassForStretchRect(
dTexVK, dst_rect, GSVector4i(destX, destY, destX + r.width(), destY + r.height()));
@@ -3106,14 +3190,13 @@ void GSDeviceVK::BeginRenderPassForStretchRect(
(allow_discard && dst_rc.eq(dtex_rc)) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : GetLoadOpForTexture(dTex);
dTex->SetState(GSTexture::State::Dirty);
if (dTex->GetType() == GSTexture::Type::DepthStencil)
if (dTex->IsDepthStencil())
{
if (load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
BeginClearRenderPass(m_utility_depth_render_pass_clear, dtex_rc, dTex->GetClearDepth(), 0);
else
BeginRenderPass((load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) ? m_utility_depth_render_pass_discard :
m_utility_depth_render_pass_load,
dtex_rc);
m_utility_depth_render_pass_load, dtex_rc);
}
else if (dTex->GetFormat() == GSTexture::Format::Color)
{
@@ -3121,8 +3204,7 @@ void GSDeviceVK::BeginRenderPassForStretchRect(
BeginClearRenderPass(m_utility_color_render_pass_clear, dtex_rc, dTex->GetClearColor());
else
BeginRenderPass((load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) ? m_utility_color_render_pass_discard :
m_utility_color_render_pass_load,
dtex_rc);
m_utility_color_render_pass_load, dtex_rc);
}
else
{
@@ -3154,7 +3236,7 @@ void GSDeviceVK::DoStretchRect(GSTextureVK* sTex, const GSVector4& sRect, GSText
SetPipeline(pipeline);
const bool is_present = (!dTex);
const bool depth = (dTex && dTex->GetType() == GSTexture::Type::DepthStencil);
const bool depth = (dTex && dTex->IsDepthStencil());
const GSVector2i size(is_present ? GSVector2i(GetWindowWidth(), GetWindowHeight()) : dTex->GetSize());
const GSVector4i dtex_rc(0, 0, size.x, size.y);
const GSVector4i dst_rc(GSVector4i(dRect).rintersect(dtex_rc));
@@ -3218,10 +3300,9 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel,
if (m_tfx_textures[0] == sTexVK)
PSSetShaderResource(0, nullptr, false);
pxAssert(
(sTexVK->GetType() == GSTexture::Type::DepthStencil) == (dTexVK->GetType() == GSTexture::Type::DepthStencil));
pxAssert(sTexVK->IsDepthStencil() == dTexVK->IsDepthStencil());
const VkImageAspectFlags aspect =
(sTexVK->GetType() == GSTexture::Type::DepthStencil) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
sTexVK->IsDepthStencil() ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
const VkImageBlit ib{{aspect, sLevel, 0u, 1u}, {{sRect.left, sRect.top, 0}, {sRect.right, sRect.bottom, 1}},
{aspect, dLevel, 0u, 1u}, {{dRect.left, dRect.top, 0}, {dRect.right, dRect.bottom, 1}}};
@@ -3825,7 +3906,8 @@ VkShaderModule GSDeviceVK::GetUtilityFragmentShader(const std::string& source, c
bool GSDeviceVK::CreateNullTexture()
{
m_null_texture = GSTextureVK::Create(GSTexture::Type::RenderTarget, GSTexture::Format::Color, 1, 1, 1);
GSTexture::Usage null_usage = m_features.rov ? GSTexture::ShaderWriteTarget : GSTexture::FeedbackTarget;
m_null_texture = GSTextureVK::Create(null_usage, GSTexture::Format::Color, 1, 1, 1);
if (!m_null_texture)
return false;
@@ -4810,6 +4892,9 @@ void GSDeviceVK::DestroyResources()
if (m_timestamp_query_pool != VK_NULL_HANDLE)
vkDestroyQueryPool(m_device, m_timestamp_query_pool, nullptr);
if (m_pipeline_statistics_query_pool != VK_NULL_HANDLE)
vkDestroyQueryPool(m_device, m_pipeline_statistics_query_pool, nullptr);
if (m_global_descriptor_pool != VK_NULL_HANDLE)
vkDestroyDescriptorPool(m_device, m_global_descriptor_pool, nullptr);
@@ -5269,7 +5354,7 @@ void GSDeviceVK::SetLineWidth(float width)
m_dirty_flags |= DIRTY_FLAG_LINE_WIDTH;
}
void GSDeviceVK::PSSetUnorderedAccess(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds)
void GSDeviceVK::PSSetROVs(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds)
{
GSTextureVK* vkRt = static_cast<GSTextureVK*>(rt);
GSTextureVK* vkDs = static_cast<GSTextureVK*>(ds);
@@ -6030,7 +6115,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
{
config.colclip_update_area = config.drawarea;
EndRenderPass();
colclip_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
colclip_rt = static_cast<GSTextureVK*>(CreateFeedbackTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
if (!colclip_rt)
{
Console.Warning("VK: Failed to allocate ColorClip render target, aborting draw.");
@@ -6186,7 +6271,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
PSSetShaderResource(TFX_TEXTURE_DEPTH, nullptr, false);
}
PSSetUnorderedAccess(draw_rt_rov, draw_ds_rov, config.ps.HasColorOutput(), config.ps.HasDepthROVWrite());
PSSetROVs(draw_rt_rov, draw_ds_rov, config.ps.HasColorOutput(), config.ps.HasDepthROVWrite());
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags), rtsize);
+21 -3
View File
@@ -209,6 +209,14 @@ private:
void CalibrateSpinTimestamp();
u64 GetCPUTimestamp();
// For pipeline statistics
enum class QueryState
{
None,
Querying,
Ready,
};
struct FrameResources
{
// [0] - Init (upload) command buffer, [1] - draw command buffer
@@ -221,6 +229,7 @@ private:
bool init_buffer_used = false;
bool needs_fence_wait = false;
bool timestamp_written = false;
QueryState pipeline_statistics_query = QueryState::None;
std::vector<std::function<void()>> cleanup_resources;
};
@@ -277,6 +286,11 @@ private:
bool m_wants_new_timestamp_calibration = false;
VkTimeDomainEXT m_calibrated_timestamp_type = VK_TIME_DOMAIN_DEVICE_EXT;
VkQueryPool m_pipeline_statistics_query_pool = VK_NULL_HANDLE;
GPUPipelineStatistics m_accumulated_gpu_pipeline_statistics{};
bool m_gpu_pipeline_statistics_enabled = false;
bool m_gpu_pipeline_statistics_supported = false;
std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources;
u64 m_next_fence_counter = 1;
u64 m_completed_fence_counter = 0;
@@ -293,6 +307,8 @@ private:
VkPhysicalDeviceDriverPropertiesKHR m_device_driver_properties = {};
OptionalExtensions m_optional_extensions = {};
u32 m_max_framebuffer_width = 0;
u32 m_max_framebuffer_height = 0;
public:
enum FeedbackLoopFlag : u8
{
@@ -468,8 +484,7 @@ private:
std::string m_tfx_source;
GSTexture* CreateSurface(
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) override;
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) final;
@@ -562,6 +577,9 @@ public:
bool SetGPUTimingEnabled(bool enabled) override;
float GetAndResetAccumulatedGPUTime() override;
bool SetGPUPipelineStatisticsEnabled(bool enabled) override;
GPUPipelineStatistics GetAndResetAccumulatedGPUPipelineStatistics() override;
void PushDebugGroup(const char* fmt, ...) override;
void PopDebugGroup() override;
void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) override;
@@ -608,7 +626,7 @@ public:
void IASetIndexBuffer(const void* index, size_t count);
void VSSetIndexBuffer(const void* index, size_t count);
void PSSetUnorderedAccess(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds);
void PSSetROVs(GSTexture* rt, GSTexture* ds, bool write_rt, bool write_ds);
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, ResourceType type = ResourceType::SRV);
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
+50 -65
View File
@@ -11,7 +11,7 @@
#include "common/Console.h"
#include "common/BitUtils.h"
VkFramebuffer GSTextureVK::CreateNullFramebuffer()
VkFramebuffer GSTextureVK::CreateNullFramebuffer(u32 w, u32 h)
{
const VkRenderPass rp = GSDeviceVK::GetInstance()->GetRenderPass(
VK_FORMAT_UNDEFINED,
@@ -23,7 +23,7 @@ VkFramebuffer GSTextureVK::CreateNullFramebuffer()
return VK_NULL_HANDLE;
Vulkan::FramebufferBuilder fbb;
fbb.SetSize(16384, 16384, 1);
fbb.SetSize(w, h, 1);
fbb.SetRenderPass(rp);
return fbb.Create(GSDeviceVK::GetInstance()->GetDevice());
@@ -61,7 +61,7 @@ static VkAccessFlagBits GetFeedbackLoopInputAccessBits()
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
}
GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image,
GSTextureVK::GSTextureVK(Usage usage, Format format, int width, int height, int levels, VkImage image,
VmaAllocation allocation, VkImageView view, VkFormat vk_format)
: GSTexture()
, m_image(image)
@@ -69,7 +69,7 @@ GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int le
, m_view(view)
, m_vk_format(vk_format)
{
m_type = type;
m_usage = usage;
m_format = format;
m_size.x = width;
m_size.y = height;
@@ -81,8 +81,10 @@ GSTextureVK::~GSTextureVK()
Destroy(true);
}
std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int width, int height, int levels)
std::unique_ptr<GSTextureVK> GSTextureVK::Create(Usage usage, Format format, int width, int height, int levels)
{
pxAssert(ValidateUsageAndFormat(usage, format));
const VkFormat vk_format = GSDeviceVK::GetInstance()->LookupNativeFormat(format);
VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, 0, VK_IMAGE_TYPE_2D, vk_format,
@@ -98,59 +100,42 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle,
{VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast<u32>(levels), 0, 1}};
switch (type)
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
if (format == Format::UNorm8)
{
case Type::Texture:
{
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
// for r8 textures, swizzle it across all 4 components. the shaders depend on it being in alpha.. why?
static constexpr const VkComponentMapping r8_swizzle = {
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R };
vci.components = r8_swizzle;
}
if (format == Format::UNorm8)
{
// for r8 textures, swizzle it across all 4 components. the shaders depend on it being in alpha.. why?
static constexpr const VkComponentMapping r8_swizzle = {
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R};
vci.components = r8_swizzle;
}
}
break;
if (IsRenderTarget(usage))
{
pxAssert(levels == 1);
ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
case Type::RenderTarget:
{
pxAssert(levels == 1);
ici.usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
}
break;
if (IsFeedback(usage))
{
ici.usage |= GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ?
VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
case Type::DepthStencil:
{
pxAssert(levels == 1);
ici.usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
break;
if (IsDepthStencil(usage))
{
ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
case Type::RWTexture:
{
pxAssert(levels == 1);
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
}
break;
default:
return {};
if (IsShaderWrite(usage))
{
ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
}
// Use dedicated allocations for typical RT size
if ((type == Type::RenderTarget || type == Type::DepthStencil) && width >= 512 && height >= 448)
if (IsRenderTargetOrDepthStencil(usage) && width >= 512 && height >= 448)
aci.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
VkImage image = VK_NULL_HANDLE;
@@ -184,17 +169,18 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
}
return std::unique_ptr<GSTextureVK>(
new GSTextureVK(type, format, width, height, levels, image, allocation, view, vk_format));
new GSTextureVK(usage, format, width, height, levels, image, allocation, view, vk_format));
}
std::unique_ptr<GSTextureVK> GSTextureVK::Adopt(
VkImage image, Type type, Format format, int width, int height, int levels, VkFormat vk_format)
VkImage image, Usage usage, Format format, int width, int height, int levels, VkFormat vk_format)
{
// Only need to create the image view, this is mainly for swap chains.
const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, image,
VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle,
{(type == Type::DepthStencil) ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
{IsDepthStencil(usage) ?
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
0u, static_cast<u32>(levels), 0u, 1u}};
// Memory is managed by the owner of the image.
@@ -207,14 +193,14 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Adopt(
}
return std::unique_ptr<GSTextureVK>(
new GSTextureVK(type, format, width, height, levels, image, VK_NULL_HANDLE, view, vk_format));
new GSTextureVK(usage, format, width, height, levels, image, VK_NULL_HANDLE, view, vk_format));
}
void GSTextureVK::Destroy(bool defer)
{
GSDeviceVK::GetInstance()->UnbindTexture(this);
if (m_type == Type::RenderTarget || m_type == Type::DepthStencil)
if (IsRenderTargetOrDepthStencil())
{
for (const auto& [other_tex, fb, feedback_color, feedback_depth] : m_framebuffers)
{
@@ -275,7 +261,7 @@ void* GSTextureVK::GetNativeHandle() const
VkCommandBuffer GSTextureVK::GetCommandBufferForUpdate()
{
if (m_type != Type::Texture || m_use_fence_counter == GSDeviceVK::GetInstance()->GetCurrentFenceCounter())
if (!IsTexture() || m_use_fence_counter == GSDeviceVK::GetInstance()->GetCurrentFenceCounter())
{
// Console.WriteLn("Texture update within frame, can't use do beforehand");
GSDeviceVK::GetInstance()->EndRenderPass();
@@ -404,7 +390,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
TransitionToLayout(cmdbuf, Layout::TransferDst);
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
if (m_type == Type::RenderTarget)
if (IsRenderTarget())
{
if (!r.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
CommitClear(cmdbuf);
@@ -416,7 +402,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
CalcUploadRowLengthFromPitch(upload_pitch), buffer, buffer_offset);
TransitionToLayout(cmdbuf, Layout::ShaderReadOnly);
if (m_type == Type::Texture)
if (IsTexture())
m_needs_mipmaps_generated |= (layer == 0);
return true;
@@ -486,7 +472,7 @@ void GSTextureVK::Unmap()
TransitionToLayout(cmdbuf, Layout::TransferDst);
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
if (m_type == Type::RenderTarget)
if (IsRenderTarget())
{
if (!m_map_area.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
CommitClear(cmdbuf);
@@ -499,7 +485,7 @@ void GSTextureVK::Unmap()
buffer_offset);
TransitionToLayout(cmdbuf, Layout::ShaderReadOnly);
if (m_type == Type::Texture)
if (IsTexture())
m_needs_mipmaps_generated |= (m_map_level == 0);
}
@@ -813,7 +799,7 @@ VkFramebuffer GSTextureVK::GetFramebuffer(bool feedback_loop)
VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool feedback_loop_color, bool feedback_loop_depth)
{
pxAssertRel(m_type != Type::Texture, "Texture is a render target");
pxAssertRel(!IsTexture(), "Texture is a render target");
for (const auto& [other_tex, fb, other_feedback_loop_color, other_feedback_loop_depth] : m_framebuffers)
{
@@ -822,9 +808,8 @@ VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool
}
const VkRenderPass rp = GSDeviceVK::GetInstance()->GetRenderPass(
(m_type != GSTexture::Type::DepthStencil) ? m_vk_format : VK_FORMAT_UNDEFINED,
(m_type != GSTexture::Type::DepthStencil) ? (depth_texture ? depth_texture->m_vk_format : VK_FORMAT_UNDEFINED) :
m_vk_format,
!IsDepthStencil() ? m_vk_format : VK_FORMAT_UNDEFINED,
!IsDepthStencil() ? (depth_texture ? depth_texture->m_vk_format : VK_FORMAT_UNDEFINED) : m_vk_format,
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, feedback_loop_color, feedback_loop_depth);
if (!rp)
+5 -5
View File
@@ -33,16 +33,16 @@ public:
~GSTextureVK() override;
static std::unique_ptr<GSTextureVK> Create(Type type, Format format, int width, int height, int levels);
static std::unique_ptr<GSTextureVK> Create(Usage usage, Format format, int width, int height, int levels);
static std::unique_ptr<GSTextureVK> Adopt(
VkImage image, Type type, Format format, int width, int height, int levels, VkFormat vk_format);
VkImage image, Usage usage, Format format, int width, int height, int levels, VkFormat vk_format);
void Destroy(bool defer);
__fi VkImage GetImage() const { return m_image; }
__fi VkImageView GetView() const { return m_view; }
__fi Layout GetLayout() const { return m_layout; }
virtual bool IsUnorderedAccess() const override { return GetLayout() == Layout::ReadWriteImage; }
bool IsShaderWriteMode() const override { return GetLayout() == Layout::ReadWriteImage; }
__fi VkFormat GetVkFormat() const { return m_vk_format; }
@@ -72,7 +72,7 @@ public:
void TransitionSubresourcesToLayout(
VkCommandBuffer command_buffer, int start_level, int num_levels, Layout old_layout, Layout new_layout);
static VkFramebuffer CreateNullFramebuffer();
static VkFramebuffer CreateNullFramebuffer(u32 w, u32 h);
/// Framebuffers are lazily allocated.
VkFramebuffer GetFramebuffer(bool feedback_loop);
@@ -83,7 +83,7 @@ public:
__fi void SetUseFenceCounter(u64 counter) { m_use_fence_counter = counter; }
private:
GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image, VmaAllocation allocation,
GSTextureVK(Usage usage, Format format, int width, int height, int levels, VkImage image, VmaAllocation allocation,
VkImageView view, VkFormat vk_format);
VkCommandBuffer GetCommandBufferForUpdate();
+1 -1
View File
@@ -463,7 +463,7 @@ bool VKSwapChain::CreateSwapChain()
for (u32 i = 0; i < image_count; i++)
{
std::unique_ptr<GSTextureVK> texture =
GSTextureVK::Adopt(images[i], GSTexture::Type::RenderTarget, GSTexture::Format::Color,
GSTextureVK::Adopt(images[i], GSTexture::RenderTarget, GSTexture::Format::Color,
m_window_info.surface_width, m_window_info.surface_height, 1, surface_format->format);
if (!texture)
return false;
+44
View File
@@ -394,6 +394,8 @@ static const char* s_gs_hw_fix_names[] = {
"minimumBlendingLevel",
"maximumBlendingLevel",
"recommendedBlendingLevel",
"recommendedAccurateAlphaTest",
"recommendedHWAA1",
"getSkipCount",
"beforeDraw",
"moveHandler",
@@ -935,6 +937,48 @@ void GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
}
break;
case GSHWFixId::RecommendedAccurateAlphaTest:
{
if (!is_sw_renderer && value >= 0 && value <= 1 &&
static_cast<int>(config.HWAccurateAlphaTest) < value)
{
Host::AddKeyedOSDMessage("HWAlphaTestWarning",
fmt::format(TRANSLATE_FS("GameDatabase",
"{0} Accurate Alpha Test is currently disabled.\n"
"This game recommends enabling Accurate Alpha Test.\n"
"You can enable it in Game Properties to improve graphical\n"
"accuracy, but this may increase system requirements."),
ICON_FA_PAINTBRUSH),
Host::OSD_WARNING_DURATION);
}
else
{
Host::RemoveKeyedOSDMessage("HWAlphaTestWarning");
}
}
break;
case GSHWFixId::RecommendedHWAA1:
{
if (!is_sw_renderer && value >= 0 && value <= 1 &&
static_cast<int>(config.HWAA1) < value)
{
Host::AddKeyedOSDMessage("HWAA1Warning",
fmt::format(TRANSLATE_FS("GameDatabase",
"{0} AA1 is currently disabled.\n"
"This game recommends enabling AA1.\n"
"You can enable it in Game Properties to improve graphical\n"
"accuracy, but this may increase system requirements."),
ICON_FA_PAINTBRUSH),
Host::OSD_WARNING_DURATION);
}
else
{
Host::RemoveKeyedOSDMessage("HWAA1Warning");
}
}
break;
case GSHWFixId::GetSkipCount:
config.GetSkipCountFunctionId = static_cast<s16>(value);
break;
+2
View File
@@ -81,6 +81,8 @@ namespace GameDatabaseSchema
MinimumBlendingLevel,
MaximumBlendingLevel,
RecommendedBlendingLevel,
RecommendedAccurateAlphaTest,
RecommendedHWAA1,
GetSkipCount,
BeforeDraw,
MoveHandler,
-10
View File
@@ -819,13 +819,3 @@ void AudioStreamParameters::LoadSave(SettingsWrapper& wrap, const char* section)
expand_high_cutoff = std::min<u8>(expand_high_cutoff, 100);
}
}
bool AudioStreamParameters::operator!=(const AudioStreamParameters& rhs) const
{
return (std::memcmp(this, &rhs, sizeof(*this)) != 0);
}
bool AudioStreamParameters::operator==(const AudioStreamParameters& rhs) const
{
return (std::memcmp(this, &rhs, sizeof(*this)) == 0);
}
+3 -2
View File
@@ -5,6 +5,8 @@
#include "common/Pcsx2Defs.h"
#include <compare>
class SettingsWrapper;
enum class AudioBackend : u8
@@ -75,6 +77,5 @@ struct AudioStreamParameters
void LoadSave(SettingsWrapper& wrap, const char* section);
bool operator==(const AudioStreamParameters& rhs) const;
bool operator!=(const AudioStreamParameters& rhs) const;
friend auto operator<=>(const AudioStreamParameters& lhs, const AudioStreamParameters& rhs) = default;
};
+2 -64
View File
@@ -4025,17 +4025,8 @@ TRANSLATE_NOOP("FullscreenUI", "empty title");
TRANSLATE_NOOP("FullscreenUI", "no serial");
TRANSLATE_NOOP("FullscreenUI", "Failed to copy text to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Download Failed");
TRANSLATE_NOOP("FullscreenUI", "Enable Achievements");
TRANSLATE_NOOP("FullscreenUI", "Achievement tracking is not currently enabled. Your login will have no effect until after tracking is enabled.\n\nDo you want to enable tracking now?");
TRANSLATE_NOOP("FullscreenUI", "Enable Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and participate in game-specific leaderboards.\n\nHowever, hardcore mode also prevents the usage of save states, cheats and slowdown functionality.\n\nDo you want to enable hardcore mode?");
TRANSLATE_NOOP("FullscreenUI", "Reset System");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?");
TRANSLATE_NOOP("FullscreenUI", "This game has no achievements.");
TRANSLATE_NOOP("FullscreenUI", "This game has no leaderboards.");
TRANSLATE_NOOP("FullscreenUI", "No file selected.");
TRANSLATE_NOOP("FullscreenUI", "Sound reset to default.");
TRANSLATE_NOOP("FullscreenUI", "Sound is already using default.");
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State");
TRANSLATE_NOOP("FullscreenUI", "Game List");
@@ -4086,31 +4077,6 @@ TRANSLATE_NOOP("FullscreenUI", "Enter one or more cover image URL templates belo
TRANSLATE_NOOP("FullscreenUI", "URLs:");
TRANSLATE_NOOP("FullscreenUI", "Saves covers using the game's title instead of serial number.");
TRANSLATE_NOOP("FullscreenUI", "Downloading covers...");
TRANSLATE_NOOP("FullscreenUI", "RetroAchievements");
TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below.\n\nYour password will not be saved in PCSX2, an access token will be generated and used instead.");
TRANSLATE_NOOP("FullscreenUI", "Username");
TRANSLATE_NOOP("FullscreenUI", "Password");
TRANSLATE_NOOP("FullscreenUI", "Logging in...");
TRANSLATE_NOOP("FullscreenUI", "Dismiss");
TRANSLATE_NOOP("FullscreenUI", "Login");
TRANSLATE_NOOP("FullscreenUI", "Cancel");
TRANSLATE_NOOP("FullscreenUI", "When enabled and logged in, PCSX2 will scan for achievements on startup.");
TRANSLATE_NOOP("FullscreenUI", "\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions.");
TRANSLATE_NOOP("FullscreenUI", "Displays popup messages on events such as achievement unlocks and leaderboard submissions.");
TRANSLATE_NOOP("FullscreenUI", "Displays popup messages when starting, submitting, or failing a leaderboard challenge.");
TRANSLATE_NOOP("FullscreenUI", "Plays sound effects for events such as achievement unlocks and leaderboard submissions.");
TRANSLATE_NOOP("FullscreenUI", "Shows icons in the screen when a challenge/primed achievement is active.");
TRANSLATE_NOOP("FullscreenUI", "Shows icons in the screen when leaderboard tracking is active.");
TRANSLATE_NOOP("FullscreenUI", "Determines where achievement/leaderboard overlays are positioned on the screen.");
TRANSLATE_NOOP("FullscreenUI", "Determines where achievement/leaderboard notification popups are positioned on the screen.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, each session will behave as if no achievements have been unlocked.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, PCSX2 will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Sound Effects");
TRANSLATE_NOOP("FullscreenUI", "Account");
TRANSLATE_NOOP("FullscreenUI", "Logs out of RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Logs in to RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Current Game");
TRANSLATE_NOOP("FullscreenUI", "An error occurred while deleting empty game settings:\n{}");
TRANSLATE_NOOP("FullscreenUI", "An error occurred while saving game settings:\n{}");
TRANSLATE_NOOP("FullscreenUI", "{} is not a valid disc image.");
@@ -4132,9 +4098,6 @@ TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to reset the play time for
TRANSLATE_NOOP("FullscreenUI", "Version: {}");
TRANSLATE_NOOP("FullscreenUI", "Error: {}");
TRANSLATE_NOOP("FullscreenUI", "Warning: {}");
TRANSLATE_NOOP("FullscreenUI", "Successfully logged in as {}.");
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
TRANSLATE_NOOP("FullscreenUI", "Failed to preview sound:\n{}");
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Backup Slot {}");
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Slot {}");
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State To Slot {}");
@@ -4149,6 +4112,7 @@ TRANSLATE_NOOP("FullscreenUI", "Last Played");
TRANSLATE_NOOP("FullscreenUI", "Size");
TRANSLATE_NOOP("FullscreenUI", "Change Selection");
TRANSLATE_NOOP("FullscreenUI", "Select");
TRANSLATE_NOOP("FullscreenUI", "Cancel");
TRANSLATE_NOOP("FullscreenUI", "Parent Directory");
TRANSLATE_NOOP("FullscreenUI", "Enter Value");
TRANSLATE_NOOP("FullscreenUI", "About");
@@ -4179,6 +4143,7 @@ TRANSLATE_NOOP("FullscreenUI", "Save Screenshot");
TRANSLATE_NOOP("FullscreenUI", "Switch To Software Renderer");
TRANSLATE_NOOP("FullscreenUI", "Switch To Hardware Renderer");
TRANSLATE_NOOP("FullscreenUI", "Change Disc");
TRANSLATE_NOOP("FullscreenUI", "Reset System");
TRANSLATE_NOOP("FullscreenUI", "Exit And Save State");
TRANSLATE_NOOP("FullscreenUI", "Delete Save");
TRANSLATE_NOOP("FullscreenUI", "Close Menu");
@@ -4207,32 +4172,5 @@ TRANSLATE_NOOP("FullscreenUI", "Close");
TRANSLATE_NOOP("FullscreenUI", "Use Title File Names");
TRANSLATE_NOOP("FullscreenUI", "Stop");
TRANSLATE_NOOP("FullscreenUI", "Start");
TRANSLATE_NOOP("FullscreenUI", "RAIntegration is being used instead of the built-in achievements implementation.");
TRANSLATE_NOOP("FullscreenUI", "Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Achievement Notifications");
TRANSLATE_NOOP("FullscreenUI", "Leaderboard Notifications");
TRANSLATE_NOOP("FullscreenUI", "Enable In-Game Overlays");
TRANSLATE_NOOP("FullscreenUI", "Enable In-Game Leaderboard Overlays");
TRANSLATE_NOOP("FullscreenUI", "Overlay Position");
TRANSLATE_NOOP("FullscreenUI", "Notification Position");
TRANSLATE_NOOP("FullscreenUI", "Encore Mode");
TRANSLATE_NOOP("FullscreenUI", "Spectator Mode");
TRANSLATE_NOOP("FullscreenUI", "Test Unofficial Achievements");
TRANSLATE_NOOP("FullscreenUI", "Select File");
TRANSLATE_NOOP("FullscreenUI", "Preview");
TRANSLATE_NOOP("FullscreenUI", "Reset to Default");
TRANSLATE_NOOP("FullscreenUI", "Notification Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Notification Sound");
TRANSLATE_NOOP("FullscreenUI", "Unlock Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Unlock Sound");
TRANSLATE_NOOP("FullscreenUI", "Leaderboard Submit Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Leaderboard Submit Sound");
TRANSLATE_NOOP("FullscreenUI", "Username: {}");
TRANSLATE_NOOP("FullscreenUI", "Login token generated on {}");
TRANSLATE_NOOP("FullscreenUI", "Logout");
TRANSLATE_NOOP("FullscreenUI", "Not Logged In");
TRANSLATE_NOOP("FullscreenUI", "Game: {0} ({1})");
TRANSLATE_NOOP("FullscreenUI", "Rich presence inactive or unsupported.");
TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements available.");
// TRANSLATION-STRING-AREA-END
#endif
+108 -10
View File
@@ -3043,6 +3043,13 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
"EmuCore/GS", "HWAA1", false);
DrawToggleSetting(
bsi, FSUI_ICONSTR(ICON_FA_BULLSEYE, "Mipmapping"), FSUI_CSTR("Enables emulation of the GS's texture mipmapping."), "EmuCore/GS", "hw_mipmap", true);
if (is_hardware && effective_renderer != GSRendererType::OGL)
{
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LAYER_GROUP, "Rasterizer Ordered View"),
FSUI_CSTR("Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games "
"with higher accuracy settings."),
"EmuCore/GS", "HWROV", false);
}
}
else
{
@@ -3295,13 +3302,6 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
if (show_advanced_settings)
{
MenuHeading(FSUI_CSTR("Advanced"));
if (is_hardware && effective_renderer != GSRendererType::OGL)
{
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LAYER_GROUP, "Rasterizer Ordered View"),
FSUI_CSTR("Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games "
"with higher accuracy settings."),
"EmuCore/GS", "HWROV", true);
}
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FORWARD, "Skip Presenting Duplicate Frames"),
FSUI_CSTR("Skips displaying frames that don't change in 25/30fps games. Can improve speed, but increase input lag/make frame pacing "
"worse."),
@@ -3461,6 +3461,8 @@ void FullscreenUI::DrawOSDSettingsPage()
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BUG, "Show GPU Debug Info"),
FSUI_CSTR("Shows debug information about the renderer."), "EmuCore/GS", "OsdShowGPUDebug", false);
#endif
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_IMAGE, "Show GPU Stats"),
FSUI_CSTR("Shows the host's GPU pipeline statistics."), "EmuCore/GS", "OsdShowGPUStats", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_HEARTBEAT_ALT, "Show Frame Times"),
FSUI_CSTR("Shows a visual history of frame times."), "EmuCore/GS", "OsdShowFrameTimes", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SLIDERS, "Show Settings"),
@@ -5724,6 +5726,8 @@ TRANSLATE_NOOP("FullscreenUI", "Game compatibility copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Game path copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "None");
TRANSLATE_NOOP("FullscreenUI", "Automatic");
TRANSLATE_NOOP("FullscreenUI", "Both slots must have a card selected to swap.");
TRANSLATE_NOOP("FullscreenUI", "Swapped Slot 1 and Slot 2 memory cards.");
TRANSLATE_NOOP("FullscreenUI", "Browse...");
TRANSLATE_NOOP("FullscreenUI", "Create New...");
TRANSLATE_NOOP("FullscreenUI", "Enter custom HDD size in gigabytes (402000):");
@@ -5740,6 +5744,15 @@ TRANSLATE_NOOP("FullscreenUI", "Folder");
TRANSLATE_NOOP("FullscreenUI", "Yes - Enable NTFS compression");
TRANSLATE_NOOP("FullscreenUI", "No - Disable NTFS compression");
TRANSLATE_NOOP("FullscreenUI", "Failed to create the Memory Card, the log may contain more information.");
TRANSLATE_NOOP("FullscreenUI", "Enable Achievements");
TRANSLATE_NOOP("FullscreenUI", "Achievement tracking is not currently enabled. Your login will have no effect until after tracking is enabled.\n\nDo you want to enable tracking now?");
TRANSLATE_NOOP("FullscreenUI", "Enable Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and participate in game-specific leaderboards.\n\nHowever, hardcore mode also prevents the usage of save states, cheats and slowdown functionality.\n\nDo you want to enable hardcore mode?");
TRANSLATE_NOOP("FullscreenUI", "Reset System");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?");
TRANSLATE_NOOP("FullscreenUI", "No file selected.");
TRANSLATE_NOOP("FullscreenUI", "Sound reset to default.");
TRANSLATE_NOOP("FullscreenUI", "Sound is already using default.");
TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to restore the default controller configuration?\n\nAll shared bindings and configuration will be lost, but your input profiles will remain.\n\nYou cannot undo this action.");
TRANSLATE_NOOP("FullscreenUI", "Controller settings reset to default.");
TRANSLATE_NOOP("FullscreenUI", "No input profiles available.");
@@ -5801,6 +5814,7 @@ TRANSLATE_NOOP("FullscreenUI", "Changes the BIOS image used to start future sess
TRANSLATE_NOOP("FullscreenUI", "BIOS Selection");
TRANSLATE_NOOP("FullscreenUI", "Fast Boot Options");
TRANSLATE_NOOP("FullscreenUI", "Skips the intro screen, and bypasses region checks.");
TRANSLATE_NOOP("FullscreenUI", "Removes emulation speed throttle until the game starts to reduce startup time.");
TRANSLATE_NOOP("FullscreenUI", "Speed Control");
TRANSLATE_NOOP("FullscreenUI", "Sets the speed when running without fast forwarding.");
TRANSLATE_NOOP("FullscreenUI", "Sets the speed when using the fast forward hotkey.");
@@ -5826,6 +5840,7 @@ TRANSLATE_NOOP("FullscreenUI", "Display");
TRANSLATE_NOOP("FullscreenUI", "Selects the aspect ratio to display the game content at.");
TRANSLATE_NOOP("FullscreenUI", "Selects the aspect ratio for display when a FMV is detected as playing.");
TRANSLATE_NOOP("FullscreenUI", "Selects the algorithm used to convert the PS2's interlaced output to progressive for display.");
TRANSLATE_NOOP("FullscreenUI", "Disables interlacing offset which may reduce blurring in some situations.");
TRANSLATE_NOOP("FullscreenUI", "Determines the resolution at which screenshots will be saved.");
TRANSLATE_NOOP("FullscreenUI", "Selects the format which will be used to save screenshots.");
TRANSLATE_NOOP("FullscreenUI", "Selects the quality at which screenshots will be compressed.");
@@ -5849,6 +5864,7 @@ TRANSLATE_NOOP("FullscreenUI", "Selects the type of dithering applies when the g
TRANSLATE_NOOP("FullscreenUI", "Determines the level of accuracy when emulating blend modes not supported by the host graphics API.");
TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's edge anti-aliasing (AA1).");
TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's texture mipmapping.");
TRANSLATE_NOOP("FullscreenUI", "Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games with higher accuracy settings.");
TRANSLATE_NOOP("FullscreenUI", "Number of threads to use in addition to the main GS thread for rasterization.");
TRANSLATE_NOOP("FullscreenUI", "Force a primitive flush when a framebuffer is also an input texture.");
TRANSLATE_NOOP("FullscreenUI", "Hardware Fixes");
@@ -5868,6 +5884,7 @@ TRANSLATE_NOOP("FullscreenUI", "Allows the texture cache to reuse as an input te
TRANSLATE_NOOP("FullscreenUI", "Flushes all targets in the texture cache back to local memory when shutting down.");
TRANSLATE_NOOP("FullscreenUI", "Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games).");
TRANSLATE_NOOP("FullscreenUI", "When enabled GPU converts colormap-textures, otherwise the CPU will. It is a trade-off between GPU and CPU.");
TRANSLATE_NOOP("FullscreenUI", "Attempts to reduce draw calls in games which do heavy context switching for blending purposes.");
TRANSLATE_NOOP("FullscreenUI", "Upscaling Fixes");
TRANSLATE_NOOP("FullscreenUI", "Adjusts vertices relative to upscaling.");
TRANSLATE_NOOP("FullscreenUI", "Attempt to do rescaling at native resolution.");
@@ -5899,7 +5916,6 @@ TRANSLATE_NOOP("FullscreenUI", "Adjusts gamma. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts saturation. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Applies a shader which replicates the visual effects of different styles of television set.");
TRANSLATE_NOOP("FullscreenUI", "Advanced");
TRANSLATE_NOOP("FullscreenUI", "Enables Rasterizer Ordered View (ROV), which allows feedback loops to be executed with fewer draw calls. Can improve performance in feedback heavy games with higher accuracy settings.");
TRANSLATE_NOOP("FullscreenUI", "Skips displaying frames that don't change in 25/30fps games. Can improve speed, but increase input lag/make frame pacing worse.");
TRANSLATE_NOOP("FullscreenUI", "Forces the use of FIFO over Mailbox presentation, i.e. double buffering instead of triple buffering. Usually results in worse frame pacing.");
TRANSLATE_NOOP("FullscreenUI", "Displays additional, very high upscaling multipliers dependent on GPU and driver capability.");
@@ -5933,6 +5949,7 @@ TRANSLATE_NOOP("FullscreenUI", "Shows the host's CPU utilization based on thread
TRANSLATE_NOOP("FullscreenUI", "Shows the host's GPU utilization.");
TRANSLATE_NOOP("FullscreenUI", "Shows indicators when fast forwarding, pausing, and other abnormal states are active.");
TRANSLATE_NOOP("FullscreenUI", "Shows debug information about the renderer.");
TRANSLATE_NOOP("FullscreenUI", "Shows the host's GPU pipeline statistics.");
TRANSLATE_NOOP("FullscreenUI", "Shows a visual history of frame times.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current configuration in the bottom-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the amount of currently active patches/cheats on the bottom-right corner of the display.");
@@ -5956,6 +5973,7 @@ TRANSLATE_NOOP("FullscreenUI", "When enabled, the minimum supported output laten
TRANSLATE_NOOP("FullscreenUI", "Settings and Operations");
TRANSLATE_NOOP("FullscreenUI", "Creates a new memory card file or folder.");
TRANSLATE_NOOP("FullscreenUI", "Simulates a larger memory card by filtering saves only to the current game.");
TRANSLATE_NOOP("FullscreenUI", "Swaps the selected memory cards in Slot 1 and Slot 2.");
TRANSLATE_NOOP("FullscreenUI", "If not set, this card will be considered unplugged.");
TRANSLATE_NOOP("FullscreenUI", "The selected memory card image will be used for this slot.");
TRANSLATE_NOOP("FullscreenUI", "Removes the current card from the slot.");
@@ -5978,6 +5996,34 @@ TRANSLATE_NOOP("FullscreenUI", "Internal HDD");
TRANSLATE_NOOP("FullscreenUI", "Enables the internal Hard Disk Drive for expanded storage.");
TRANSLATE_NOOP("FullscreenUI", "Changes the HDD image used for PS2 internal storage.");
TRANSLATE_NOOP("FullscreenUI", "HDD Image Selection");
TRANSLATE_NOOP("FullscreenUI", "RetroAchievements");
TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below.\n\nYour password will not be saved in PCSX2, an access token will be generated and used instead.");
TRANSLATE_NOOP("FullscreenUI", "Username");
TRANSLATE_NOOP("FullscreenUI", "Password");
TRANSLATE_NOOP("FullscreenUI", "Logging in...");
TRANSLATE_NOOP("FullscreenUI", "Dismiss");
TRANSLATE_NOOP("FullscreenUI", "Login");
TRANSLATE_NOOP("FullscreenUI", "Cancel");
TRANSLATE_NOOP("FullscreenUI", "Settings");
TRANSLATE_NOOP("FullscreenUI", "When enabled and logged in, PCSX2 will scan for achievements on startup.");
TRANSLATE_NOOP("FullscreenUI", "\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions.");
TRANSLATE_NOOP("FullscreenUI", "Displays popup messages on events such as achievement unlocks and leaderboard submissions.");
TRANSLATE_NOOP("FullscreenUI", "Displays popup messages when starting, submitting, or failing a leaderboard challenge.");
TRANSLATE_NOOP("FullscreenUI", "Plays sound effects for events such as achievement unlocks and leaderboard submissions.");
TRANSLATE_NOOP("FullscreenUI", "Shows icons in the screen when a challenge/primed achievement is active.");
TRANSLATE_NOOP("FullscreenUI", "Shows icons in the screen when leaderboard tracking is active.");
TRANSLATE_NOOP("FullscreenUI", "Determines where achievement/leaderboard overlays are positioned on the screen.");
TRANSLATE_NOOP("FullscreenUI", "Determines where achievement/leaderboard notification popups are positioned on the screen.");
TRANSLATE_NOOP("FullscreenUI", "Determines the display duration for achievement unlock popups.");
TRANSLATE_NOOP("FullscreenUI", "Determines the display duration for leaderboard popups.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, each session will behave as if no achievements have been unlocked.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server.");
TRANSLATE_NOOP("FullscreenUI", "When enabled, PCSX2 will list achievements from unofficial sets. These achievements are not tracked by RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Sound Effects");
TRANSLATE_NOOP("FullscreenUI", "Account");
TRANSLATE_NOOP("FullscreenUI", "Logs out of RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Logs in to RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Current Game");
TRANSLATE_NOOP("FullscreenUI", "Configuration");
TRANSLATE_NOOP("FullscreenUI", "Replaces these settings with a previously saved input profile.");
TRANSLATE_NOOP("FullscreenUI", "Stores the current settings to an input profile.");
@@ -5999,6 +6045,9 @@ TRANSLATE_NOOP("FullscreenUI", "Determines the pressure required to activate the
TRANSLATE_NOOP("FullscreenUI", "Toggle every %d frames");
TRANSLATE_NOOP("FullscreenUI", "Clears all bindings for this USB controller.");
TRANSLATE_NOOP("FullscreenUI", "Data Save Locations");
TRANSLATE_NOOP("FullscreenUI", "Organization");
TRANSLATE_NOOP("FullscreenUI", "Saves snapshots to per-game subfolders instead of a shared folder.");
TRANSLATE_NOOP("FullscreenUI", "Saves video recordings to per-game subfolders instead of a shared folder.");
TRANSLATE_NOOP("FullscreenUI", "Changing these options may cause games to become non-functional. Modify at your own risk, the PCSX2 team will not provide support for configurations with these settings changed.");
TRANSLATE_NOOP("FullscreenUI", "Logging");
TRANSLATE_NOOP("FullscreenUI", "Writes log messages to the system console (console window/standard output).");
@@ -6017,6 +6066,8 @@ TRANSLATE_NOOP("FullscreenUI", "Enables simulation of the EE's cache. Slow.");
TRANSLATE_NOOP("FullscreenUI", "Huge speedup for some games, with almost no compatibility side effects.");
TRANSLATE_NOOP("FullscreenUI", "Moderate speedup for some games, with no known side effects.");
TRANSLATE_NOOP("FullscreenUI", "Uses backpatching to avoid register flushing on every memory access.");
TRANSLATE_NOOP("FullscreenUI", "Pauses the virtual machine when a TLB miss occurs, instead of ignoring it and continuing.");
TRANSLATE_NOOP("FullscreenUI", "Exposes additional memory to the virtual machine, expanding the EE and IOP memory to 128MB and 8MB respectively.");
TRANSLATE_NOOP("FullscreenUI", "Vector Units");
TRANSLATE_NOOP("FullscreenUI", "New Vector Unit recompiler with much improved compatibility. Recommended.");
TRANSLATE_NOOP("FullscreenUI", "Good speedup and high compatibility, may cause graphical errors.");
@@ -6029,7 +6080,9 @@ TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate.");
TRANSLATE_NOOP("FullscreenUI", "Graphics");
TRANSLATE_NOOP("FullscreenUI", "Enables API-level validation of graphics commands.");
TRANSLATE_NOOP("FullscreenUI", "Forces SW blending and disables several optimizations.");
TRANSLATE_NOOP("FullscreenUI", "Settings");
TRANSLATE_NOOP("FullscreenUI", "PINE Settings");
TRANSLATE_NOOP("FullscreenUI", "Enables the PINE Inter-Process Communication system, allowing external programs to interact with the emulator.");
TRANSLATE_NOOP("FullscreenUI", "The network port slot used for PINE IPC connections.");
TRANSLATE_NOOP("FullscreenUI", "No cheats are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "Cheat Codes");
TRANSLATE_NOOP("FullscreenUI", "No patches are available for this game.");
@@ -6072,6 +6125,9 @@ TRANSLATE_NOOP("FullscreenUI", "HDD image '{}' already exists. Do you want to ov
TRANSLATE_NOOP("FullscreenUI", "Failed to create the Memory Card, because the name '{}' contains one or more invalid characters.");
TRANSLATE_NOOP("FullscreenUI", "Failed to create the Memory Card, because another card with the name '{}' already exists.");
TRANSLATE_NOOP("FullscreenUI", "Memory Card '{}' created.");
TRANSLATE_NOOP("FullscreenUI", "Successfully logged in as {}.");
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
TRANSLATE_NOOP("FullscreenUI", "Failed to preview sound:\n{}");
TRANSLATE_NOOP("FullscreenUI", "Failed to load '{}'.");
TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' loaded.");
TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' saved.");
@@ -6302,6 +6358,8 @@ TRANSLATE_NOOP("FullscreenUI", "Internal");
TRANSLATE_NOOP("FullscreenUI", "Negative");
TRANSLATE_NOOP("FullscreenUI", "Positive");
TRANSLATE_NOOP("FullscreenUI", "Chop/Zero (Default)");
TRANSLATE_NOOP("FullscreenUI", "Nearest (Default)");
TRANSLATE_NOOP("FullscreenUI", "Chop/Zero");
TRANSLATE_NOOP("FullscreenUI", "Deflate");
TRANSLATE_NOOP("FullscreenUI", "Zstandard");
TRANSLATE_NOOP("FullscreenUI", "Low (Fast)");
@@ -6356,6 +6414,7 @@ TRANSLATE_NOOP("FullscreenUI", "Start Big Picture UI");
TRANSLATE_NOOP("FullscreenUI", "Reset Settings");
TRANSLATE_NOOP("FullscreenUI", "Change Search Directory");
TRANSLATE_NOOP("FullscreenUI", "Fast Boot");
TRANSLATE_NOOP("FullscreenUI", "Fast Forward Boot");
TRANSLATE_NOOP("FullscreenUI", "Normal Speed");
TRANSLATE_NOOP("FullscreenUI", "Fast Forward Speed");
TRANSLATE_NOOP("FullscreenUI", "Slow Motion Speed");
@@ -6375,6 +6434,7 @@ TRANSLATE_NOOP("FullscreenUI", "Use Host VSync Timing");
TRANSLATE_NOOP("FullscreenUI", "Aspect Ratio");
TRANSLATE_NOOP("FullscreenUI", "FMV Aspect Ratio Override");
TRANSLATE_NOOP("FullscreenUI", "Deinterlacing");
TRANSLATE_NOOP("FullscreenUI", "Disable Interlace Offset");
TRANSLATE_NOOP("FullscreenUI", "Screenshot Size");
TRANSLATE_NOOP("FullscreenUI", "Screenshot Format");
TRANSLATE_NOOP("FullscreenUI", "Screenshot Quality");
@@ -6395,6 +6455,7 @@ TRANSLATE_NOOP("FullscreenUI", "Dithering");
TRANSLATE_NOOP("FullscreenUI", "Blending Accuracy");
TRANSLATE_NOOP("FullscreenUI", "Edge AA (AA1)");
TRANSLATE_NOOP("FullscreenUI", "Mipmapping");
TRANSLATE_NOOP("FullscreenUI", "Rasterizer Ordered View");
TRANSLATE_NOOP("FullscreenUI", "Software Rendering Threads");
TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Software)");
TRANSLATE_NOOP("FullscreenUI", "Manual Hardware Fixes");
@@ -6415,6 +6476,7 @@ TRANSLATE_NOOP("FullscreenUI", "Texture Inside RT");
TRANSLATE_NOOP("FullscreenUI", "Read Targets When Closing");
TRANSLATE_NOOP("FullscreenUI", "Estimate Texture Region");
TRANSLATE_NOOP("FullscreenUI", "GPU Palette Conversion");
TRANSLATE_NOOP("FullscreenUI", "Draw Buffering");
TRANSLATE_NOOP("FullscreenUI", "Half Pixel Offset");
TRANSLATE_NOOP("FullscreenUI", "Native Scaling");
TRANSLATE_NOOP("FullscreenUI", "Round Sprite");
@@ -6441,7 +6503,6 @@ TRANSLATE_NOOP("FullscreenUI", "Shade Boost Contrast");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Gamma");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Saturation");
TRANSLATE_NOOP("FullscreenUI", "TV Shaders");
TRANSLATE_NOOP("FullscreenUI", "Rasterizer Ordered View");
TRANSLATE_NOOP("FullscreenUI", "Skip Presenting Duplicate Frames");
TRANSLATE_NOOP("FullscreenUI", "Disable Mailbox Presentation");
TRANSLATE_NOOP("FullscreenUI", "Extended Upscaling Multipliers");
@@ -6474,6 +6535,7 @@ TRANSLATE_NOOP("FullscreenUI", "Show CPU Usage");
TRANSLATE_NOOP("FullscreenUI", "Show GPU Usage");
TRANSLATE_NOOP("FullscreenUI", "Show Status Indicators");
TRANSLATE_NOOP("FullscreenUI", "Show GPU Debug Info");
TRANSLATE_NOOP("FullscreenUI", "Show GPU Stats");
TRANSLATE_NOOP("FullscreenUI", "Show Frame Times");
TRANSLATE_NOOP("FullscreenUI", "Show Settings");
TRANSLATE_NOOP("FullscreenUI", "Show Patches");
@@ -6494,6 +6556,7 @@ TRANSLATE_NOOP("FullscreenUI", "Minimal Output Latency");
TRANSLATE_NOOP("FullscreenUI", "Create Memory Card");
TRANSLATE_NOOP("FullscreenUI", "Memory Card Directory");
TRANSLATE_NOOP("FullscreenUI", "Folder Memory Card Filter");
TRANSLATE_NOOP("FullscreenUI", "Swap Memory Cards");
TRANSLATE_NOOP("FullscreenUI", "Enable Network Adapter");
TRANSLATE_NOOP("FullscreenUI", "Ethernet Device Type");
TRANSLATE_NOOP("FullscreenUI", "Ethernet Device");
@@ -6515,6 +6578,35 @@ TRANSLATE_NOOP("FullscreenUI", "Create");
TRANSLATE_NOOP("FullscreenUI", "File Already Exists");
TRANSLATE_NOOP("FullscreenUI", "Memory Card Type");
TRANSLATE_NOOP("FullscreenUI", "Use NTFS Compression?");
TRANSLATE_NOOP("FullscreenUI", "RAIntegration is being used instead of the built-in achievements implementation.");
TRANSLATE_NOOP("FullscreenUI", "Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Achievement Notifications");
TRANSLATE_NOOP("FullscreenUI", "Leaderboard Notifications");
TRANSLATE_NOOP("FullscreenUI", "Enable In-Game Overlays");
TRANSLATE_NOOP("FullscreenUI", "Enable In-Game Leaderboard Overlays");
TRANSLATE_NOOP("FullscreenUI", "Overlay Position");
TRANSLATE_NOOP("FullscreenUI", "Notification Position");
TRANSLATE_NOOP("FullscreenUI", "Unlock Notification Duration");
TRANSLATE_NOOP("FullscreenUI", "Leaderboard Notification Duration");
TRANSLATE_NOOP("FullscreenUI", "Encore Mode");
TRANSLATE_NOOP("FullscreenUI", "Spectator Mode");
TRANSLATE_NOOP("FullscreenUI", "Test Unofficial Achievements");
TRANSLATE_NOOP("FullscreenUI", "Select File");
TRANSLATE_NOOP("FullscreenUI", "Preview");
TRANSLATE_NOOP("FullscreenUI", "Reset to Default");
TRANSLATE_NOOP("FullscreenUI", "Notification Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Notification Sound");
TRANSLATE_NOOP("FullscreenUI", "Unlock Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Unlock Sound");
TRANSLATE_NOOP("FullscreenUI", "Leaderboard Submit Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Leaderboard Submit Sound");
TRANSLATE_NOOP("FullscreenUI", "Username: {}");
TRANSLATE_NOOP("FullscreenUI", "Login token generated on {}");
TRANSLATE_NOOP("FullscreenUI", "Logout");
TRANSLATE_NOOP("FullscreenUI", "Not Logged In");
TRANSLATE_NOOP("FullscreenUI", "Game: {0} ({1})");
TRANSLATE_NOOP("FullscreenUI", "Rich presence inactive or unsupported.");
TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements available.");
TRANSLATE_NOOP("FullscreenUI", "Reset Controller Settings");
TRANSLATE_NOOP("FullscreenUI", "Load Profile");
TRANSLATE_NOOP("FullscreenUI", "Save Profile");
@@ -6554,6 +6646,8 @@ TRANSLATE_NOOP("FullscreenUI", "Cheats Directory");
TRANSLATE_NOOP("FullscreenUI", "Patches Directory");
TRANSLATE_NOOP("FullscreenUI", "Texture Replacements Directory");
TRANSLATE_NOOP("FullscreenUI", "Video Dumping Directory");
TRANSLATE_NOOP("FullscreenUI", "Save Snapshots in Game-Specific Folders");
TRANSLATE_NOOP("FullscreenUI", "Save Video Recordings in Game-Specific Folders");
TRANSLATE_NOOP("FullscreenUI", "Show Advanced Settings");
TRANSLATE_NOOP("FullscreenUI", "System Console");
TRANSLATE_NOOP("FullscreenUI", "File Logging");
@@ -6570,6 +6664,8 @@ TRANSLATE_NOOP("FullscreenUI", "Enable EE Cache");
TRANSLATE_NOOP("FullscreenUI", "Enable INTC Spin Detection");
TRANSLATE_NOOP("FullscreenUI", "Enable Wait Loop Detection");
TRANSLATE_NOOP("FullscreenUI", "Enable Fast Memory Access");
TRANSLATE_NOOP("FullscreenUI", "Pause On TLB Miss");
TRANSLATE_NOOP("FullscreenUI", "Enable Extended RAM (Dev Console)");
TRANSLATE_NOOP("FullscreenUI", "VU0 Rounding Mode");
TRANSLATE_NOOP("FullscreenUI", "VU0 Clamping Mode");
TRANSLATE_NOOP("FullscreenUI", "VU1 Rounding Mode");
@@ -6583,6 +6679,8 @@ TRANSLATE_NOOP("FullscreenUI", "Compression Method");
TRANSLATE_NOOP("FullscreenUI", "Compression Level");
TRANSLATE_NOOP("FullscreenUI", "Use Debug Device");
TRANSLATE_NOOP("FullscreenUI", "Use Debug Blend");
TRANSLATE_NOOP("FullscreenUI", "Enable PINE");
TRANSLATE_NOOP("FullscreenUI", "PINE Slot");
TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack");
TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For FMVs");
TRANSLATE_NOOP("FullscreenUI", "Skip MPEG Hack");
+3
View File
@@ -267,6 +267,9 @@ void ImGuiManager::WindowResized()
// Scale might have changed as a result of window resize.
RequestScaleUpdate();
if (GImGui->NavWindow != nullptr)
ImGui::NavInitWindow(GImGui->NavWindow, true);
}
void ImGuiManager::RequestScaleUpdate()
+37 -1
View File
@@ -71,6 +71,7 @@ std::vector<SmallString> s_software_thread_lines;
SmallString s_capture_line;
SmallString s_gpu_usage_line;
SmallString s_gpu_debug_info_line;
SmallString s_gpu_stats_line;
SmallString s_speed_icon;
constexpr ImU32 white_color = IM_COL32(255, 255, 255, 255);
@@ -439,7 +440,19 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
DRAW_LINE(osd_font, font_size, s_hardware_info_cpu_line.c_str(), white_color);
// GPU
s_hardware_info_gpu_line.format("GPU: {}{}", g_gs_device->GetName(), GSConfig.UseDebugDevice ? " (Debug)" : "");
const char* gpu_suffix = "";
if (GSConfig.UseDebugDevice && GSConfig.HWROV)
gpu_suffix = " (Debug & ROV)";
else if (GSConfig.UseDebugDevice)
gpu_suffix = " (Debug)";
else if (GSConfig.HWROV)
gpu_suffix = " (ROV)";
s_hardware_info_gpu_line.format(
"GPU: {}{}",
g_gs_device->GetName(),
gpu_suffix);
DRAW_LINE(osd_font, font_size, s_hardware_info_gpu_line.c_str(), white_color);
}
@@ -504,6 +517,24 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
}
#endif
}
if (GSConfig.OsdShowGPUStats)
{
const auto FormatUnits = [](double val) {
if (val >= 1e9)
return fmt::format("{:.5}B", val / 1e9);
if (val >= 1e6)
return fmt::format("{:.5}M", val / 1e6);
if (val >= 1e3)
return fmt::format("{:.5}K", val / 1e3);
return fmt::format("{:.5}", val);
};
s_gpu_stats_line.format("VSI: {} | PSI: {}",
FormatUnits(PerformanceMetrics::GetGPUAverageVSInvocations()),
FormatUnits(PerformanceMetrics::GetGPUAveragePSInvocations()));
DRAW_LINE(osd_font, font_size, s_gpu_stats_line.c_str(), white_color);
}
}
// No refresh yet. Display cached lines.
else
@@ -556,6 +587,11 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
DRAW_LINE(osd_font, font_size, s_gpu_debug_info_line.c_str(), white_color);
#endif
}
if (GSConfig.OsdShowGPUStats)
{
DRAW_LINE(osd_font, font_size, s_gpu_stats_line.c_str(), white_color);
}
}
// Check every OSD frame because this is an animation.
+1 -1
View File
@@ -75,7 +75,7 @@ bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
}
HRESULT hr =
create(GetModuleHandleA(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, reinterpret_cast<LPVOID*>(m_dinput.put()), nullptr);
create(GetModuleHandleA(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, m_dinput.put_void(), nullptr);
if (FAILED(hr))
{
Console.Error("DirectInput8Create() failed: %08X", hr);
+1 -1
View File
@@ -139,7 +139,7 @@ void SysMemory::DumpMemoryMap()
DUMP_REGION("R5900 Recompiler Cache", s_code_memory, HostMemoryMap::EErecOffset, HostMemoryMap::EErecSize);
DUMP_REGION("R3000A Recompiler Cache", s_code_memory, HostMemoryMap::IOPrecOffset, HostMemoryMap::IOPrecSize);
DUMP_REGION("Micro VU0 Recompiler Cache", s_code_memory, HostMemoryMap::mVU0recOffset, HostMemoryMap::mVU0recSize);
DUMP_REGION("Micro VU0 Recompiler Cache", s_code_memory, HostMemoryMap::mVU1recOffset, HostMemoryMap::mVU1recSize);
DUMP_REGION("Micro VU1 Recompiler Cache", s_code_memory, HostMemoryMap::mVU1recOffset, HostMemoryMap::mVU1recSize);
DUMP_REGION("VIF0 Unpack Recompiler Cache", s_code_memory, HostMemoryMap::VIF0recOffset, HostMemoryMap::VIF0recSize);
DUMP_REGION("VIF1 Unpack Recompiler Cache", s_code_memory, HostMemoryMap::VIF1recOffset, HostMemoryMap::VIF1recSize);
DUMP_REGION("VIF Unpack Recompiler Cache", s_code_memory, HostMemoryMap::VIFUnpackRecOffset, HostMemoryMap::VIFUnpackRecSize);
+9 -9
View File
@@ -4,11 +4,11 @@
#include "BuildVersion.h"
#include "Common.h"
#include "Host.h"
#include "Memory.h"
#include "Elfheader.h"
#include "SaveState.h"
#include "PINE.h"
#include "VMManager.h"
#include "vtlb.h"
#include "common/Error.h"
#include "common/Threading.h"
@@ -538,7 +538,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 1, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
const u8 res = memRead8(a);
const u8 res = vtlb_ramRead<mem8_t>(a);
ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 1;
buf_cnt += 4;
@@ -551,7 +551,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 2, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
const u16 res = memRead16(a);
const u16 res = vtlb_ramRead<mem16_t>(a);
ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 2;
buf_cnt += 4;
@@ -564,7 +564,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 4, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
const u32 res = memRead32(a);
const u32 res = vtlb_ramRead<mem32_t>(a);
ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 4;
buf_cnt += 4;
@@ -577,7 +577,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 8, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
const u64 res = memRead64(a);
const u64 res = vtlb_ramRead<mem64_t>(a);
ToResultVector(ret_buffer, res, ret_cnt);
ret_cnt += 8;
buf_cnt += 4;
@@ -590,7 +590,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 1 + 4, ret_cnt, 0, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
memWrite8(a, FromSpan<u8>(buf, buf_cnt + 4));
vtlb_ramWrite<mem8_t>(a, FromSpan<u8>(buf, buf_cnt + 4));
buf_cnt += 5;
break;
}
@@ -601,7 +601,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 2 + 4, ret_cnt, 0, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
memWrite16(a, FromSpan<u16>(buf, buf_cnt + 4));
vtlb_ramWrite<mem16_t>(a, FromSpan<u16>(buf, buf_cnt + 4));
buf_cnt += 6;
break;
}
@@ -612,7 +612,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 4 + 4, ret_cnt, 0, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
memWrite32(a, FromSpan<u32>(buf, buf_cnt + 4));
vtlb_ramWrite<mem32_t>(a, FromSpan<u32>(buf, buf_cnt + 4));
buf_cnt += 8;
break;
}
@@ -623,7 +623,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8
if (!SafetyChecks(buf_cnt, 8 + 4, ret_cnt, 0, buf_size)) [[unlikely]]
goto error;
const u32 a = FromSpan<u32>(buf, buf_cnt);
memWrite64(a, FromSpan<u64>(buf, buf_cnt + 4));
vtlb_ramWrite<mem64_t>(a, FromSpan<u64>(buf, buf_cnt + 4));
buf_cnt += 12;
break;
}
+3 -1
View File
@@ -733,6 +733,7 @@ Pcsx2Config::GSOptions::GSOptions()
OsdShowCPU = false;
OsdShowGPU = false;
OsdShowGPUDebug = false;
OsdShowGPUStats = false;
OsdShowIndicators = true;
OsdShowFrameTimes = false;
OsdShowHardwareInfo = false;
@@ -755,7 +756,7 @@ Pcsx2Config::GSOptions::GSOptions()
HWAccurateAlphaTest = false;
HWAA1 = false;
UseDebugBlend = false;
HWROV = true;
HWROV = false;
HWROVLogging = false;
HWROVBarriersVK = false;
@@ -966,6 +967,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(OsdShowCPU);
SettingsWrapBitBool(OsdShowGPU);
SettingsWrapBitBool(OsdShowGPUDebug);
SettingsWrapBitBool(OsdShowGPUStats);
SettingsWrapBitBool(OsdShowResolution);
SettingsWrapBitBool(OsdShowGSStats);
SettingsWrapBitBool(OsdShowIndicators);
+21 -1
View File
@@ -70,6 +70,10 @@ static float s_average_gpu_time = 0.0f;
static float s_accumulated_gpu_time = 0.0f;
static float s_gpu_usage = 0.0f;
static u32 s_presents_since_last_update = 0;
static double s_average_gpu_vs_invocations = 0.0;
static double s_average_gpu_ps_invocations = 0.0;
static u64 s_accumulated_gpu_vs_invocations = 0;
static u64 s_accumulated_gpu_ps_invocations = 0;
void PerformanceMetrics::Clear()
{
@@ -156,8 +160,12 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit, bool is_sk
s_maximum_frame_time = std::exchange(s_maximum_frame_time_accumulator, 0.0f);
s_fps = static_cast<float>(s_frames_since_last_update) / time;
s_average_gpu_time = s_accumulated_gpu_time / static_cast<float>(s_unskipped_frames_since_last_update);
s_average_gpu_vs_invocations = static_cast<double>(s_accumulated_gpu_vs_invocations) / static_cast<double>(s_unskipped_frames_since_last_update);
s_average_gpu_ps_invocations = static_cast<double>(s_accumulated_gpu_ps_invocations) / static_cast<double>(s_unskipped_frames_since_last_update);
s_gpu_usage = s_accumulated_gpu_time / (time * 10.0f);
s_accumulated_gpu_time = 0.0f;
s_accumulated_gpu_vs_invocations = 0;
s_accumulated_gpu_ps_invocations = 0;
// prefer privileged register write based framerate detection, it's less likely to have false positives
if (s_gs_privileged_register_writes_since_last_update > 0 && !EmuConfig.Gamefixes.BlitInternalFPSHack)
@@ -228,9 +236,11 @@ void PerformanceMetrics::Update(bool gs_register_write, bool fb_blit, bool is_sk
Host::OnPerformanceMetricsUpdated();
}
void PerformanceMetrics::OnGPUPresent(float gpu_time)
void PerformanceMetrics::OnGPUPresent(float gpu_time, u64 vs_invocations, u64 ps_invocations)
{
s_accumulated_gpu_time += gpu_time;
s_accumulated_gpu_vs_invocations += vs_invocations;
s_accumulated_gpu_ps_invocations += ps_invocations;
s_presents_since_last_update++;
}
@@ -362,6 +372,16 @@ float PerformanceMetrics::GetGPUAverageTime()
return s_average_gpu_time;
}
double PerformanceMetrics::GetGPUAverageVSInvocations()
{
return s_average_gpu_vs_invocations;
}
double PerformanceMetrics::GetGPUAveragePSInvocations()
{
return s_average_gpu_ps_invocations;
}
const PerformanceMetrics::FrameTimeHistory& PerformanceMetrics::GetFrameTimeHistory()
{
return s_frame_time_history;
+3 -1
View File
@@ -21,7 +21,7 @@ namespace PerformanceMetrics
void Clear();
void Reset();
void Update(bool gs_register_write, bool fb_blit, bool is_skipping_present);
void OnGPUPresent(float gpu_time);
void OnGPUPresent(float gpu_time, u64 vs_invocations, u64 ps_invocations);
/// Sets the EE thread for CPU usage calculations.
void SetCPUThread(Threading::ThreadHandle thread);
@@ -57,6 +57,8 @@ namespace PerformanceMetrics
float GetGPUUsage();
float GetGPUAverageTime();
double GetGPUAverageVSInvocations();
double GetGPUAveragePSInvocations();
const FrameTimeHistory& GetFrameTimeHistory();
u32 GetFrameTimeHistoryPos();
+1 -1
View File
@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 101; // Last changed in PR 14547
static constexpr u32 SHADER_CACHE_VERSION = 105; // Last changed in PR 14465
+29 -57
View File
@@ -19,9 +19,6 @@
#pragma clang diagnostic ignored "-Wmicrosoft-goto"
#endif
#define safe_release(ptr) \
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
namespace usb_eyetoy
{
namespace windows_api
@@ -68,7 +65,7 @@ namespace usb_eyetoy
return devList;
}
IEnumMoniker* pEnum = nullptr;
wil::com_ptr_nothrow<IEnumMoniker> pEnum;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
if (hr != S_OK)
{
@@ -76,20 +73,18 @@ namespace usb_eyetoy
return devList;
};
IMoniker* pMoniker = nullptr;
wil::com_ptr_nothrow<IMoniker> pMoniker;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK)
{
IPropertyBag* pPropBag = nullptr;
wil::com_ptr_nothrow<IPropertyBag> pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (FAILED(hr))
{
Console.Warning("Camera: BindToStorage err : %x", hr);
pMoniker->Release();
continue;
}
VARIANT var;
VariantInit(&var);
wil::unique_variant var;
hr = pPropBag->Read(L"Description", &var, 0);
if (FAILED(hr))
{
@@ -99,14 +94,9 @@ namespace usb_eyetoy
{
std::string u8name(StringUtil::WideStringToUTF8String(var.bstrVal));
devList.emplace_back(u8name, u8name);
VariantClear(&var);
}
pPropBag->Release();
pMoniker->Release();
}
pEnum->Release();
CoUninitialize();
return devList;
@@ -131,14 +121,14 @@ namespace usb_eyetoy
return -1;
}
hr = pGraphBuilder->SetFiltergraph(pGraph);
hr = pGraphBuilder->SetFiltergraph(pGraph.get());
if (FAILED(hr))
{
Console.Warning("Camera: SetFiltergraph err : %x", hr);
return -1;
}
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if (FAILED(hr))
{
Console.Warning("Camera: QueryInterface IID_IMediaControl err : %x", hr);
@@ -154,7 +144,7 @@ namespace usb_eyetoy
return -1;
}
IEnumMoniker* pEnum = nullptr;
wil::com_ptr_nothrow<IEnumMoniker> pEnum;
hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
if (hr != S_OK)
{
@@ -164,21 +154,20 @@ namespace usb_eyetoy
pEnum->Reset();
IMoniker* pMoniker = nullptr;
wil::com_ptr_nothrow<IMoniker> pMoniker;
while (pEnum->Next(1, &pMoniker, NULL) == S_OK && sourcefilter == nullptr)
{
LONGLONG start = 0, stop = MAXLONGLONG;
IPropertyBag* pPropBag = nullptr;
wil::com_ptr_nothrow<IPropertyBag> pPropBag;
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
if (FAILED(hr))
{
Console.Warning("Camera: BindToStorage err : %x", hr);
goto freeMoniker;
break;
}
VARIANT var;
VariantInit(&var);
wil::unique_variant var;
hr = pPropBag->Read(L"Description", &var, 0);
if (FAILED(hr))
{
@@ -187,24 +176,24 @@ namespace usb_eyetoy
if (FAILED(hr))
{
Console.Warning("Camera: Read name err : %x", hr);
goto freeVar;
break;
}
Console.Warning("Camera: '%ls'", var.bstrVal);
if (!selectedDevice.empty() && selectedDevice != var.bstrVal)
{
goto freeVar;
break;
}
//add a filter for the device
hr = pGraph->AddSourceFilterForMoniker(pMoniker, NULL, L"sourcefilter", &sourcefilter);
hr = pGraph->AddSourceFilterForMoniker(pMoniker.get(), NULL, L"sourcefilter", &sourcefilter);
if (FAILED(hr))
{
Console.Warning("Camera: AddSourceFilterForMoniker err : %x", hr);
goto freeVar;
break;
}
hr = pGraphBuilder->FindInterface(
&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter, IID_IAMStreamConfig, (void**)&pSourceConfig);
&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter.get(), IID_PPV_ARGS(&pSourceConfig));
if (SUCCEEDED(hr))
{
int iCount = 0, iSize = 0;
@@ -248,14 +237,14 @@ namespace usb_eyetoy
if (FAILED(hr))
{
Console.Warning("Camera: CoCreateInstance CLSID_SampleGrabber err : %x", hr);
goto freeVar;
break;
}
hr = pGraph->AddFilter(samplegrabberfilter, L"samplegrabberfilter");
hr = pGraph->AddFilter(samplegrabberfilter.get(), L"samplegrabberfilter");
if (FAILED(hr))
{
Console.Warning("Camera: AddFilter samplegrabberfilter err : %x", hr);
goto freeVar;
break;
}
//set mediatype on the samplegrabber
@@ -263,7 +252,7 @@ namespace usb_eyetoy
if (FAILED(hr))
{
Console.Warning("Camera: QueryInterface err : %x", hr);
goto freeVar;
break;
}
AM_MEDIA_TYPE mt;
@@ -274,7 +263,7 @@ namespace usb_eyetoy
if (FAILED(hr))
{
Console.Warning("Camera: SetMediaType err : %x", hr);
goto freeVar;
break;
}
//add the callback to the samplegrabber
@@ -282,7 +271,7 @@ namespace usb_eyetoy
if (hr != S_OK)
{
Console.Warning("Camera: SetCallback err : %x", hr);
goto freeVar;
break;
}
//set the null renderer
@@ -290,40 +279,32 @@ namespace usb_eyetoy
if (FAILED(hr))
{
Console.Warning("Camera: CoCreateInstance CLSID_NullRenderer err : %x", hr);
goto freeVar;
break;
}
hr = pGraph->AddFilter(nullrenderer, L"nullrenderer");
hr = pGraph->AddFilter(nullrenderer.get(), L"nullrenderer");
if (FAILED(hr))
{
Console.Warning("Camera: AddFilter nullrenderer err : %x", hr);
goto freeVar;
break;
}
//set the render path
hr = pGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, sourcefilter, samplegrabberfilter, nullrenderer);
hr = pGraphBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, sourcefilter.get(), samplegrabberfilter.get(), nullrenderer.get());
if (FAILED(hr))
{
Console.Warning("Camera: RenderStream err : %x", hr);
goto freeVar;
break;
}
// if the stream is started, start capturing immediatly
hr = pGraphBuilder->ControlStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter, &start, &stop, 1, 2);
hr = pGraphBuilder->ControlStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, sourcefilter.get(), &start, &stop, 1, 2);
if (FAILED(hr))
{
Console.Warning("Camera: ControlStream err : %x", hr);
goto freeVar;
break;
}
freeVar:
VariantClear(&var);
pPropBag->Release();
freeMoniker:
pMoniker->Release();
}
pEnum->Release();
if (sourcefilter == nullptr)
{
return -1;
@@ -575,17 +556,8 @@ namespace usb_eyetoy
{
this->Stop();
pControl->Stop();
safe_release(sourcefilter);
safe_release(pSourceConfig);
safe_release(samplegrabberfilter);
safe_release(samplegrabber);
safe_release(nullrenderer);
}
safe_release(pGraphBuilder);
safe_release(pGraph);
safe_release(pControl);
dshowCoInitialize.reset();
return 0;
};
+8 -8
View File
@@ -84,15 +84,15 @@ namespace usb_eyetoy
private:
wil::unique_couninitialize_call dshowCoInitialize{false};
ICaptureGraphBuilder2* pGraphBuilder;
IFilterGraph2* pGraph;
IMediaControl* pControl;
wil::com_ptr_nothrow<ICaptureGraphBuilder2> pGraphBuilder;
wil::com_ptr_nothrow<IFilterGraph2> pGraph;
wil::com_ptr_nothrow<IMediaControl> pControl;
IBaseFilter* sourcefilter;
IAMStreamConfig* pSourceConfig;
IBaseFilter* samplegrabberfilter;
ISampleGrabber* samplegrabber;
IBaseFilter* nullrenderer;
wil::com_ptr_nothrow<IBaseFilter> sourcefilter;
wil::com_ptr_nothrow<IAMStreamConfig> pSourceConfig;
wil::com_ptr_nothrow<IBaseFilter> samplegrabberfilter;
wil::com_ptr_nothrow<ISampleGrabber> samplegrabber;
wil::com_ptr_nothrow<IBaseFilter> nullrenderer;
class CallbackHandler : public ISampleGrabberCB
{
+5 -13
View File
@@ -64,6 +64,7 @@
#include <atomic>
#include <mutex>
#include <sstream>
#include <common/RedtapeWilCom.h>
#ifdef _WIN32
#include "common/RedtapeWindows.h"
@@ -2493,13 +2494,13 @@ void LogGPUCapabilities()
{
Console.WriteLn(Color_StrongBlack, "Graphics Adapters Detected:");
#if defined(_WIN32)
IDXGIFactory1* pFactory = nullptr;
if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory)))
wil::com_ptr_nothrow<IDXGIFactory1> pFactory;
if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(pFactory.put()))))
return;
UINT i = 0;
IDXGIAdapter* pAdapter = nullptr;
while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND)
wil::com_ptr_nothrow<IDXGIAdapter> pAdapter;
while (pFactory->EnumAdapters(i, pAdapter.put()) != DXGI_ERROR_NOT_FOUND)
{
DXGI_ADAPTER_DESC desc;
LARGE_INTEGER umdver;
@@ -2515,21 +2516,12 @@ void LogGPUCapabilities()
umdver.QuadPart & 0xFFFF);
i++;
pAdapter->Release();
pAdapter = nullptr;
}
else
{
pAdapter->Release();
pAdapter = nullptr;
break;
}
}
if (pAdapter)
pAdapter->Release();
pFactory->Release();
#else
// Credits to neofetch for the following (modified) script
std::string gpu_script = R"gpu_script(
+17 -12
View File
@@ -323,24 +323,29 @@ template void vtlb_memWrite<mem32_t>(u32 mem, mem32_t data);
template void vtlb_memWrite<mem64_t>(u32 mem, mem64_t data);
template <typename DataType>
bool vtlb_ramRead(u32 addr, DataType* value)
DataType vtlb_ramRead(u32 addr, bool* result)
{
const auto vmv = vtlbdata.vmap[addr >> VTLB_PAGE_BITS];
if (vmv.isHandler(addr))
if (vmv.isHandler(addr)) [[unlikely]]
{
std::memset(value, 0, sizeof(DataType));
return false;
if (result)
*result = false;
return {};
}
std::memcpy(value, reinterpret_cast<DataType*>(vmv.assumePtr(addr)), sizeof(DataType));
return true;
DataType value = {};
std::memcpy(&value, reinterpret_cast<DataType*>(vmv.assumePtr(addr)), sizeof(DataType));
if (result)
*result = true;
return value;
}
template <typename DataType>
bool vtlb_ramWrite(u32 addr, const DataType& data)
{
const auto vmv = vtlbdata.vmap[addr >> VTLB_PAGE_BITS];
if (vmv.isHandler(addr))
if (vmv.isHandler(addr)) [[unlikely]]
return false;
std::memcpy(reinterpret_cast<DataType*>(vmv.assumePtr(addr)), &data, sizeof(DataType));
@@ -348,11 +353,11 @@ bool vtlb_ramWrite(u32 addr, const DataType& data)
}
template bool vtlb_ramRead<mem8_t>(u32 mem, mem8_t* value);
template bool vtlb_ramRead<mem16_t>(u32 mem, mem16_t* value);
template bool vtlb_ramRead<mem32_t>(u32 mem, mem32_t* value);
template bool vtlb_ramRead<mem64_t>(u32 mem, mem64_t* value);
template bool vtlb_ramRead<mem128_t>(u32 mem, mem128_t* value);
template mem8_t vtlb_ramRead<mem8_t>(u32 mem, bool* result);
template mem16_t vtlb_ramRead<mem16_t>(u32 mem, bool* result);
template mem32_t vtlb_ramRead<mem32_t>(u32 mem, bool* result);
template mem64_t vtlb_ramRead<mem64_t>(u32 mem, bool* result);
template mem128_t vtlb_ramRead<mem128_t>(u32 mem, bool* result);
template bool vtlb_ramWrite<mem8_t>(u32 mem, const mem8_t& data);
template bool vtlb_ramWrite<mem16_t>(u32 mem, const mem16_t& data);
template bool vtlb_ramWrite<mem32_t>(u32 mem, const mem32_t& data);
+1 -1
View File
@@ -95,7 +95,7 @@ extern void TAKES_R128 vtlb_memWrite128(u32 mem, r128 value);
// These routines only access the various RAM, and will not call handlers
// which has the potential to change hardware state.
template <typename DataType>
extern DataType vtlb_ramRead(u32 mem);
extern DataType vtlb_ramRead(u32 mem, bool* result = nullptr);
template <typename DataType>
extern bool vtlb_ramWrite(u32 mem, const DataType& value);
+66 -30
View File
@@ -99,6 +99,65 @@ static void iopRecError(int err);
#ifdef DUMP_BLOCKS
static ZydisFormatterFunc s_old_print_address;
static ZydisFormatterFunc s_old_print_disp;
static bool Address2Symbol(u64 address, SmallString &buf)
{
#define A(x) ((u64)(x))
if (address >= A(iopMem->Main) && address < A(iopMem->P))
{
buf.append_format("iopMem+0x{:08X}", static_cast<u32>(address - A(iopMem->Main)));
}
else if (address >= A(&psxRegs.GPR) && address < A(&psxRegs.CP0))
{
buf.append_format("psxRegs.GPR.{}", R3000A::disRNameGPR[static_cast<u32>(address - A(&psxRegs)) / 4u]);
}
else if (address == A(&psxRegs.pc))
{
buf.append("psxRegs.pc");
}
else if (address == A(&psxRegs.cycle))
{
buf.append("psxRegs.cycle");
}
else if (address == A(&psxRegs.iopNextEventCycle))
{
buf.append("psxRegs.iopNextEventCycle");
}
else
{
return false;
}
#undef A
return true;
}
static ZyanStatus ZydisFormatterPrintDisplacement(const ZydisFormatter* formatter,
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
{
u64 address = (u64)R3000A_TEXTPTR + context->operand->mem.disp.value;
bool did_print = false;
SmallString buf;
// hardcoded RTEXTPTR
if (context->operand->mem.base == ZYDIS_REGISTER_RBX) {
did_print = Address2Symbol(address, buf);
}
if (did_print)
{
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_SYMBOL));
ZyanString* string;
ZYAN_CHECK(ZydisFormatterBufferGetString(buffer, &string));
return ZyanStringAppendFormat(string, "-%s+&%s", "R3000A_TEXTPTR", buf.c_str());
}
return s_old_print_disp(formatter, buffer, context);
}
static ZyanStatus ZydisFormatterPrintAddressAbsolute(const ZydisFormatter* formatter,
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
@@ -107,40 +166,17 @@ static ZyanStatus ZydisFormatterPrintAddressAbsolute(const ZydisFormatter* forma
ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
context->runtime_address, &address));
char buf[128];
u32 len = 0;
SmallString buf;
bool did_print = false;
#define A(x) ((u64)(x))
did_print = Address2Symbol(address, buf);
if (address >= A(iopMem->Main) && address < A(iopMem->P))
{
len = snprintf(buf, sizeof(buf), "iopMem+0x%08X", static_cast<u32>(address - A(iopMem->Main)));
}
else if (address >= A(&psxRegs.GPR) && address < A(&psxRegs.CP0))
{
len = snprintf(buf, sizeof(buf), "psxRegs.GPR.%s", R3000A::disRNameGPR[static_cast<u32>(address - A(&psxRegs)) / 4u]);
}
else if (address == A(&psxRegs.pc))
{
len = snprintf(buf, sizeof(buf), "psxRegs.pc");
}
else if (address == A(&psxRegs.cycle))
{
len = snprintf(buf, sizeof(buf), "psxRegs.cycle");
}
else if (address == A(&psxRegs.iopNextEventCycle))
{
len = snprintf(buf, sizeof(buf), "psxRegs.iopNextEventCycle");
}
#undef A
if (len > 0)
if (did_print)
{
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, ZYDIS_TOKEN_SYMBOL));
ZyanString* string;
ZYAN_CHECK(ZydisFormatterBufferGetString(buffer, &string));
return ZyanStringAppendFormat(string, "&%s", buf);
return ZyanStringAppendFormat(string, "&%s", buf.c_str());
}
return s_old_print_address(formatter, buffer, context);
@@ -918,8 +954,6 @@ static void recReserve()
pxFailRel("Failed to allocate R3000 InstCache array.");
}
#define R3000A_TEXTPTR (&psxRegs.GPR.r[33])
void recResetIOP()
{
DevCon.WriteLn("iR3000A Recompiler reset.");
@@ -1473,6 +1507,8 @@ void psxRecompileNextInstruction(bool delayslot, bool swapped_delayslot)
ZydisFormatterInit(&disas_formatter, ZYDIS_FORMATTER_STYLE_INTEL);
s_old_print_address = (ZydisFormatterFunc)&ZydisFormatterPrintAddressAbsolute;
ZydisFormatterSetHook(&disas_formatter, ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS, (const void**)&s_old_print_address);
s_old_print_disp = (ZydisFormatterFunc)&ZydisFormatterPrintDisplacement;
ZydisFormatterSetHook(&disas_formatter, ZYDIS_FORMATTER_FUNC_PRINT_DISP, (const void**)&s_old_print_disp);
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More