mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 09:44:17 +02:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f0f3b92b3 | |||
| fe3ce7f578 | |||
| 51c995168a | |||
| f83e4ff4bf | |||
| b67e793283 | |||
| d87ec54a5f | |||
| a6b1040caf | |||
| 9650c4b79a | |||
| 3f8eb5adf0 | |||
| 99a78f9a55 | |||
| c3ace64205 | |||
| 3b2c1ec6e3 | |||
| dba432639e | |||
| 166c4491c2 | |||
| d1cd5a62ed | |||
| b11a406519 | |||
| c7042e1877 | |||
| 896e0b82c2 | |||
| 7856757087 | |||
| b0ce5d7582 | |||
| e23416aa92 | |||
| 9a9cfca706 | |||
| 59feb88ef7 | |||
| 247cda0e26 | |||
| 9f3233224e | |||
| ef14238b4e | |||
| 13b7345189 | |||
| 48ca476a2f | |||
| 57ef8e7c25 | |||
| d09ce46700 | |||
| 3afc1c2663 | |||
| 5821762870 | |||
| 86b7a19f19 | |||
| cc85cef17c | |||
| 5f08f523c2 | |||
| b612959682 | |||
| aea83d5ece | |||
| 07aa5786e5 | |||
| 5bd70aff90 | |||
| 22b8d52311 | |||
| ee6c7e6286 | |||
| 66ea4c4967 | |||
| a6769818fd | |||
| 95535215aa | |||
| eadb46c5ac | |||
| b2b7943dbe | |||
| a0a261db50 | |||
| 8e73dea7e2 | |||
| e2a3670d65 | |||
| 342db51523 | |||
| 414f1660ed | |||
| cd9530eec3 | |||
| 53675cf5ce | |||
| e0566546c6 | |||
| 6c4a8efe25 | |||
| a8db6587cb | |||
| 1d8fb3d407 | |||
| 2d09d53805 |
@@ -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: |
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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: "철권 4"
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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&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&ull Titles (Grid View)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGridViewZoomIn">
|
||||
<property name="icon">
|
||||
<iconset theme="zoom-in-line"/>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -26,6 +26,7 @@ private Q_SLOTS:
|
||||
void onClearOsdFontPathClicked();
|
||||
void onSelectAllClicked();
|
||||
void onDeselectAllClicked();
|
||||
void setAllCheckboxes(bool checked);
|
||||
|
||||
private:
|
||||
void loadOsdFontPathSetting();
|
||||
|
||||
@@ -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>
|
||||
|
||||
+3114
-2806
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 |
@@ -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>
|
||||
|
||||
@@ -774,6 +774,7 @@ struct Pcsx2Config
|
||||
OsdShowCPU : 1,
|
||||
OsdShowGPU : 1,
|
||||
OsdShowGPUDebug : 1,
|
||||
OsdShowGPUStats : 1,
|
||||
OsdShowIndicators : 1,
|
||||
OsdShowFrameTimes : 1,
|
||||
OsdShowHardwareInfo : 1,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -81,6 +81,8 @@ namespace GameDatabaseSchema
|
||||
MinimumBlendingLevel,
|
||||
MaximumBlendingLevel,
|
||||
RecommendedBlendingLevel,
|
||||
RecommendedAccurateAlphaTest,
|
||||
RecommendedHWAA1,
|
||||
GetSkipCount,
|
||||
BeforeDraw,
|
||||
MoveHandler,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 (40–2000):");
|
||||
@@ -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");
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user