mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-02 21:01:58 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f199597158 | |||
| 9c313fb787 | |||
| eec29b83f3 | |||
| a57041d62f | |||
| 4956bc86c3 | |||
| e8b1dc7c0b | |||
| e81d170458 | |||
| 7ed7e5e31d | |||
| eb32b8766a | |||
| a484e6c34b | |||
| 84490a7d6f | |||
| 933f79af95 | |||
| f532357793 | |||
| ab92e5fa52 | |||
| 791880f9bf | |||
| e058a15074 | |||
| 6313800aee | |||
| 5428dbbd14 | |||
| 9694216ad7 | |||
| 4fbdc133dd | |||
| f210f16e8c | |||
| 20bf6bc282 | |||
| 99e95eebb1 | |||
| eb9280dedf | |||
| 8b8034a2a0 | |||
| 9a0e6b3c28 | |||
| defb8bf2e2 | |||
| 6295d23581 | |||
| 7f85c6e282 | |||
| 39b2c79985 | |||
| a27d35463e | |||
| 5606edd1a6 | |||
| cd003e5ec9 |
@@ -112,11 +112,6 @@ Files: src/yuzu/*.ui
|
|||||||
Copyright: 2018-2022 yuzu Emulator Project
|
Copyright: 2018-2022 yuzu Emulator Project
|
||||||
License: GPL-2.0-or-later
|
License: GPL-2.0-or-later
|
||||||
|
|
||||||
Files: src/yuzu/compatdb.ui
|
|
||||||
src/yuzu/main.ui
|
|
||||||
Copyright: 2014-2017 Citra Emulator Project
|
|
||||||
License: GPL-2.0-or-later
|
|
||||||
|
|
||||||
Files: src/yuzu/loading_screen.ui
|
Files: src/yuzu/loading_screen.ui
|
||||||
Copyright: 2019 James Rowe <jroweboy@gmail.com>
|
Copyright: 2019 James Rowe <jroweboy@gmail.com>
|
||||||
License: GPL-2.0-or-later
|
License: GPL-2.0-or-later
|
||||||
|
|||||||
@@ -281,25 +281,6 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(compat_base dist/compatibility_list/compatibility_list)
|
|
||||||
set(compat_qrc ${compat_base}.qrc)
|
|
||||||
set(compat_json ${compat_base}.json)
|
|
||||||
|
|
||||||
configure_file(${PROJECT_SOURCE_DIR}/${compat_qrc}
|
|
||||||
${PROJECT_BINARY_DIR}/${compat_qrc}
|
|
||||||
COPYONLY)
|
|
||||||
|
|
||||||
if (EXISTS ${PROJECT_SOURCE_DIR}/${compat_json})
|
|
||||||
configure_file("${PROJECT_SOURCE_DIR}/${compat_json}"
|
|
||||||
"${PROJECT_BINARY_DIR}/${compat_json}"
|
|
||||||
COPYONLY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# TODO: Compat list download
|
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${compat_json})
|
|
||||||
file(WRITE ${PROJECT_BINARY_DIR}/${compat_json} "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX))
|
if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX))
|
||||||
set(HAS_NCE 1)
|
set(HAS_NCE 1)
|
||||||
add_compile_definitions(HAS_NCE=1)
|
add_compile_definitions(HAS_NCE=1)
|
||||||
|
|||||||
-354
@@ -1,354 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "the-legend-of-zelda-breath-of-the-wild",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01007EF00011E000"}
|
|
||||||
],
|
|
||||||
"title": "The Legend of Zelda: Breath of the Wild"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "super-mario-odyssey",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100000000010000"}
|
|
||||||
],
|
|
||||||
"title": "Super Mario Odyssey"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "animal-crossing-new-horizons",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01006F8002326000"}
|
|
||||||
],
|
|
||||||
"title": "Animal Crossing: New Horizons"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "pokemon-legends-z-a",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100F43008C44000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Legends: Z-A"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "the-legend-of-zelda-tears-of-the-kingdom",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100F2C0115B6000"}
|
|
||||||
],
|
|
||||||
"title": "The Legend of Zelda: Tears of the Kingdom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "super-mario-galaxy",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010099C022B96000"}
|
|
||||||
],
|
|
||||||
"title": "Super Mario Galaxy"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 3,
|
|
||||||
"directory": "star-wars-republic-commando",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100FA10115F8000"}
|
|
||||||
],
|
|
||||||
"title": "Star Wars: Republic Commando"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "doki-doki-literature-club-plus",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010086901543E000"}
|
|
||||||
],
|
|
||||||
"title": "Doki Doki Literature Club Plus"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "pokemon-scarlet",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100A3D008C5C000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Scarlet"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "pokemon-violet",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01008F6008C5E000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Violet"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "pokemon-legends-arceus",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01001E300D162000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Legends: Arceus"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "splatoon-2",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01003BC0000A0000"}
|
|
||||||
],
|
|
||||||
"title": "Splatoon 2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "super-smash-bros-ultimate",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01006A800016E000"}
|
|
||||||
],
|
|
||||||
"title": "Super Smash Bros. Ultimate"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "mario-kart-8-deluxe",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100152000022000"}
|
|
||||||
],
|
|
||||||
"title": "Mario Kart 8 Deluxe"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "splatoon-3",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100C2500FC20000"}
|
|
||||||
],
|
|
||||||
"title": "Splatoon 3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "new-super-mario-bros-u-deluxe",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100EA80032EA000"}
|
|
||||||
],
|
|
||||||
"title": "New Super Mario Bros. U Deluxe"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "hyrule-warriors-age-of-calamity",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01002B00111A2000"}
|
|
||||||
],
|
|
||||||
"title": "Hyrule Warriors: Age of Calamity"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "luigis-mansion-3",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100DCA0064A6000"}
|
|
||||||
],
|
|
||||||
"title": "Luigi's Mansion 3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "pokemon-brilliant-diamond",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100000011D90000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Brilliant Diamond"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "pokemon-shining-pearl",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010018E011D92000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Shining Pearl"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "super-mario-3d-world-bowsers-fury",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010028600EBDA000"}
|
|
||||||
],
|
|
||||||
"title": "Super Mario 3D World + Bowser's Fury"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "the-legend-of-zelda-links-awakening",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01006BB00C6F0000"}
|
|
||||||
],
|
|
||||||
"title": "The Legend of Zelda: Link's Awakening"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "fire-emblem-three-houses",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010055D009F78000"}
|
|
||||||
],
|
|
||||||
"title": "Fire Emblem: Three Houses"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "metroid-dread",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010093801237C000"}
|
|
||||||
],
|
|
||||||
"title": "Metroid Dread"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "paper-mario-the-origami-king",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100A3900C3E2000"}
|
|
||||||
],
|
|
||||||
"title": "Paper Mario: The Origami King"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "xenoblade-chronicles-definitive-edition",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100FF500E34A000"}
|
|
||||||
],
|
|
||||||
"title": "Xenoblade Chronicles: Definitive Edition"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "xenoblade-chronicles-3",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010074F013262000"}
|
|
||||||
],
|
|
||||||
"title": "Xenoblade Chronicles 3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "pikmin-3-deluxe",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100F8600D4B0000"}
|
|
||||||
],
|
|
||||||
"title": "Pikmin 3 Deluxe"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "donkey-kong-country-tropical-freeze",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100C1F0054B6000"}
|
|
||||||
],
|
|
||||||
"title": "Donkey Kong Country: Tropical Freeze"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "kirby-and-the-forgotten-land",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01004D300C5AE000"}
|
|
||||||
],
|
|
||||||
"title": "Kirby and the Forgotten Land"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "mario-party-superstars",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01006B400D8B2000"}
|
|
||||||
],
|
|
||||||
"title": "Mario Party Superstars"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "clubhouse-games-51-worldwide-classics",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100F8600D4B0000"}
|
|
||||||
],
|
|
||||||
"title": "Clubhouse Games: 51 Worldwide Classics"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "ring-fit-adventure",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01006B300BAF8000"}
|
|
||||||
],
|
|
||||||
"title": "Ring Fit Adventure"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "arms",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01009B500007C000"}
|
|
||||||
],
|
|
||||||
"title": "ARMS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "super-mario-maker-2",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01009B90006DC000"}
|
|
||||||
],
|
|
||||||
"title": "Super Mario Maker 2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "pokemon-lets-go-pikachu",
|
|
||||||
"releases": [
|
|
||||||
{"id": "010003F003A34000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon: Let's Go, Pikachu!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "pokemon-lets-go-eevee",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100187003A36000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon: Let's Go, Eevee!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "pokemon-sword",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100ABF008968000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Sword"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "pokemon-shield",
|
|
||||||
"releases": [
|
|
||||||
{"id": "01008DB008C2C000"}
|
|
||||||
],
|
|
||||||
"title": "Pokémon Shield"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "new-pokemon-snap",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100F4300C182000"}
|
|
||||||
],
|
|
||||||
"title": "New Pokémon Snap"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "mario-golf-super-rush",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100C9C00E25C000"}
|
|
||||||
],
|
|
||||||
"title": "Mario Golf: Super Rush"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 1,
|
|
||||||
"directory": "mario-tennis-aces",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100BDE00862A000"}
|
|
||||||
],
|
|
||||||
"title": "Mario Tennis Aces"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 2,
|
|
||||||
"directory": "wario-ware-get-it-together",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100563010F22000"}
|
|
||||||
],
|
|
||||||
"title": "WarioWare: Get It Together!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"compatibility": 0,
|
|
||||||
"directory": "big-brain-academy-brain-vs-brain",
|
|
||||||
"releases": [
|
|
||||||
{"id": "0100190010F24000"}
|
|
||||||
],
|
|
||||||
"title": "Big Brain Academy: Brain vs. Brain"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<RCC>
|
|
||||||
<qresource prefix="compatibility_list">
|
|
||||||
<file>compatibility_list.json</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
Vendored
+603
-755
File diff suppressed because it is too large
Load Diff
Vendored
+592
-749
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+581
-741
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+581
-743
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+579
-736
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+580
-739
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+625
-777
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+580
-739
File diff suppressed because it is too large
Load Diff
Vendored
+580
-740
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+580
-740
File diff suppressed because it is too large
Load Diff
Vendored
+580
-739
File diff suppressed because it is too large
Load Diff
Vendored
+580
-737
File diff suppressed because it is too large
Load Diff
Vendored
+580
-740
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
Vendored
+581
-741
File diff suppressed because it is too large
Load Diff
Vendored
+578
-735
File diff suppressed because it is too large
Load Diff
-1
@@ -16,7 +16,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
||||||
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
||||||
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
||||||
ANTIFLICKER("antiflicker"),
|
|
||||||
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
|
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
|
||||||
EMULATE_BGR565("emulate_bgr565"),
|
EMULATE_BGR565("emulate_bgr565"),
|
||||||
RESCALE_HACK("rescale_hack"),
|
RESCALE_HACK("rescale_hack"),
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||||||
|
|
||||||
RENDERER_DYNA_STATE("dyna_state"),
|
RENDERER_DYNA_STATE("dyna_state"),
|
||||||
DMA_ACCURACY("dma_accuracy"),
|
DMA_ACCURACY("dma_accuracy"),
|
||||||
|
GPU_FENCE_BEHAVIOR("gpu_fence_behavior"),
|
||||||
FRAME_PACING_MODE("frame_pacing_mode"),
|
FRAME_PACING_MODE("frame_pacing_mode"),
|
||||||
AUDIO_OUTPUT_ENGINE("output_engine"),
|
AUDIO_OUTPUT_ENGINE("output_engine"),
|
||||||
MAX_ANISOTROPY("max_anisotropy"),
|
MAX_ANISOTROPY("max_anisotropy"),
|
||||||
|
|||||||
+10
-8
@@ -594,7 +594,7 @@ abstract class SettingsItem(
|
|||||||
IntSetting.ANDROID_PIPELINE_WORKERS,
|
IntSetting.ANDROID_PIPELINE_WORKERS,
|
||||||
titleId = R.string.pipeline_worker_cores,
|
titleId = R.string.pipeline_worker_cores,
|
||||||
descriptionId = R.string.pipeline_worker_cores_description,
|
descriptionId = R.string.pipeline_worker_cores_description,
|
||||||
min = 4,
|
min = 1,
|
||||||
max = 8,
|
max = 8,
|
||||||
units = "cores"
|
units = "cores"
|
||||||
)
|
)
|
||||||
@@ -669,6 +669,15 @@ abstract class SettingsItem(
|
|||||||
valuesId = R.array.dmaAccuracyValues
|
valuesId = R.array.dmaAccuracyValues
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
put(
|
||||||
|
SingleChoiceSetting(
|
||||||
|
IntSetting.GPU_FENCE_BEHAVIOR,
|
||||||
|
titleId = R.string.gpu_fence_behavior,
|
||||||
|
descriptionId = R.string.gpu_fence_behavior_description,
|
||||||
|
choicesId = R.array.gpuFenceBehaviorNames,
|
||||||
|
valuesId = R.array.gpuFenceBehaviorValues
|
||||||
|
)
|
||||||
|
)
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
|
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
|
||||||
@@ -757,13 +766,6 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.skip_cpu_inner_invalidation_description
|
descriptionId = R.string.skip_cpu_inner_invalidation_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SwitchSetting(
|
|
||||||
BooleanSetting.ANTIFLICKER,
|
|
||||||
titleId = R.string.antiflicker,
|
|
||||||
descriptionId = R.string.antiflicker_description
|
|
||||||
)
|
|
||||||
)
|
|
||||||
put(
|
put(
|
||||||
SwitchSetting(
|
SwitchSetting(
|
||||||
BooleanSetting.FIX_BLOOM_EFFECTS,
|
BooleanSetting.FIX_BLOOM_EFFECTS,
|
||||||
|
|||||||
+1
-1
@@ -283,6 +283,7 @@ class SettingsFragmentPresenter(
|
|||||||
|
|
||||||
add(IntSetting.RENDERER_ACCURACY.key)
|
add(IntSetting.RENDERER_ACCURACY.key)
|
||||||
add(IntSetting.DMA_ACCURACY.key)
|
add(IntSetting.DMA_ACCURACY.key)
|
||||||
|
add(IntSetting.GPU_FENCE_BEHAVIOR.key)
|
||||||
add(IntSetting.MAX_ANISOTROPY.key)
|
add(IntSetting.MAX_ANISOTROPY.key)
|
||||||
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
|
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
|
||||||
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
|
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
|
||||||
@@ -299,7 +300,6 @@ class SettingsFragmentPresenter(
|
|||||||
|
|
||||||
add(IntSetting.FAST_GPU_TIME.key)
|
add(IntSetting.FAST_GPU_TIME.key)
|
||||||
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
||||||
add(BooleanSetting.ANTIFLICKER.key)
|
|
||||||
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
||||||
add(BooleanSetting.EMULATE_BGR565.key)
|
add(BooleanSetting.EMULATE_BGR565.key)
|
||||||
add(BooleanSetting.RESCALE_HACK.key)
|
add(BooleanSetting.RESCALE_HACK.key)
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ namespace AndroidSettings {
|
|||||||
&show_performance_overlay};
|
&show_performance_overlay};
|
||||||
|
|
||||||
|
|
||||||
Settings::Setting<s32> pipeline_worker_count{linkage, 4, "pipeline_worker_count",
|
Settings::Setting<s32> pipeline_worker_count{linkage, 2, "pipeline_worker_count",
|
||||||
Settings::Category::Android,
|
Settings::Category::Android,
|
||||||
Settings::Specialization::Default,
|
Settings::Specialization::Default,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -476,6 +476,8 @@
|
|||||||
<string name="renderer_accuracy_description">يتحكم في وضع محاكاة وحدة معالجة الرسومات. تعمل معظم الألعاب بشكل جيد مع وضعي سريع أو متوازن، لكن الوضع الدقيق لا يزال مطلوبًا لبعض الألعاب. تميل الجسيمات إلى العرض بشكل صحيح فقط عند استخدام الوضع الدقيق.</string>
|
<string name="renderer_accuracy_description">يتحكم في وضع محاكاة وحدة معالجة الرسومات. تعمل معظم الألعاب بشكل جيد مع وضعي سريع أو متوازن، لكن الوضع الدقيق لا يزال مطلوبًا لبعض الألعاب. تميل الجسيمات إلى العرض بشكل صحيح فقط عند استخدام الوضع الدقيق.</string>
|
||||||
<string name="dma_accuracy">دقة DMA</string>
|
<string name="dma_accuracy">دقة DMA</string>
|
||||||
<string name="dma_accuracy_description">يتحكم في دقة DMA. يمكن أن تؤدي الدقة الآمنة إلى حل المشكلات في بعض الألعاب، ولكنها قد تؤثر أيضًا على الأداء في بعض الحالات. إذا لم تكن متأكدًا، فاترك هذا الخيار على الإعداد الافتراضي.</string>
|
<string name="dma_accuracy_description">يتحكم في دقة DMA. يمكن أن تؤدي الدقة الآمنة إلى حل المشكلات في بعض الألعاب، ولكنها قد تؤثر أيضًا على الأداء في بعض الحالات. إذا لم تكن متأكدًا، فاترك هذا الخيار على الإعداد الافتراضي.</string>
|
||||||
|
<string name="gpu_fence_behavior">سلوك حاجز وحدة معالجة الرسومات</string>
|
||||||
|
<string name="gpu_fence_behavior_description">يتحكم في سلوك تزامن حاجز وحدة معالجة الرسوميات. الخيار الفوري هو الأسرع، لكنه قد يسبب بعض المشاكل. الخيار المتوازن يقدم توافقًا أفضل وقد يصلح مشاكل في بعض الألعاب. الخيار الدقيق يحسن التوافق أكثر لكنه قد يقلل الأداء قليلاً. الخيار الصارم هو الأبطأ، لكنه قد يصلح المشاكل التي تتطلب تزامنًا أكثر صرامة. الإعداد الافتراضي يتبع إعداد دقة وحدة معالجة الرسوميات.</string>
|
||||||
<string name="anisotropic_filtering">تصفية متباينة الخواص</string>
|
<string name="anisotropic_filtering">تصفية متباينة الخواص</string>
|
||||||
<string name="anisotropic_filtering_description">يحسن جودة الأنسجة عند عرضها بزوايا مائلة</string>
|
<string name="anisotropic_filtering_description">يحسن جودة الأنسجة عند عرضها بزوايا مائلة</string>
|
||||||
<string name="vram_usage_mode">وضع استخدام ذاكرة VRAM</string>
|
<string name="vram_usage_mode">وضع استخدام ذاكرة VRAM</string>
|
||||||
@@ -497,6 +499,8 @@
|
|||||||
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
|
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
|
||||||
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
|
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
|
||||||
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
|
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
|
||||||
|
<string name="enable_gpu_buffer_readback">تفعيل قراءة مخزن وحدة معالجة الرسومات</string>
|
||||||
|
<string name="enable_gpu_buffer_readback_description">يحافظ هذا النظام على بيانات المخزن المؤقت المُعدّلة بواسطة وحدة معالجة الرسومات عن طريق قراءتها مرة أخرى قبل التحميل. تتطلب بعض الألعاب ذلك لعرض بعض التأثيرات بشكل صحيح. قد يُسبب ذلك مشاكل إذا لم يتمكن الجهاز من التعامل مع عبء العمل الإضافي.</string>
|
||||||
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
|
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
|
||||||
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
|
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
|
||||||
|
|
||||||
@@ -506,8 +510,6 @@
|
|||||||
<string name="fast_gpu_time_description">يُجبر هذا الخيار معظم الألعاب على العمل بأعلى دقة عرض أصلية. استخدم 256 للحصول على أقصى أداء و512 للحصول على أعلى جودة رسومات.</string>
|
<string name="fast_gpu_time_description">يُجبر هذا الخيار معظم الألعاب على العمل بأعلى دقة عرض أصلية. استخدم 256 للحصول على أقصى أداء و512 للحصول على أعلى جودة رسومات.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
|
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
|
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
|
||||||
<string name="antiflicker">مضاد الوميض</string>
|
|
||||||
<string name="antiflicker_description">يُجبر هذا الوضع وظائف وحدة معالجة الرسومات على الانتظار حتى يتم إرسال العمل إليها. استخدمه مع وضع وحدة معالجة الرسومات السريع لتجنب الوميض مع تأثير أقل على الأداء.</string>
|
|
||||||
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
|
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
|
||||||
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
|
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
|
||||||
<string name="emulate_bgr565">محاكاة BGR565</string>
|
<string name="emulate_bgr565">محاكاة BGR565</string>
|
||||||
@@ -573,6 +575,12 @@
|
|||||||
<string name="gpu_log_level_description">مستوى التفاصيل لسجلات وحدة معالجة الرسومات (كلما زاد المستوى، زادت التفاصيل وزادت التكاليف الإضافية)</string>
|
<string name="gpu_log_level_description">مستوى التفاصيل لسجلات وحدة معالجة الرسومات (كلما زاد المستوى، زادت التفاصيل وزادت التكاليف الإضافية)</string>
|
||||||
<string name="gpu_log_vulkan_calls">تسجيل استدعاءات واجهة برمجة تطبيقات Vulkan</string>
|
<string name="gpu_log_vulkan_calls">تسجيل استدعاءات واجهة برمجة تطبيقات Vulkan</string>
|
||||||
<string name="gpu_log_vulkan_calls_description">تتبع جميع استدعاءات واجهة برمجة تطبيقات Vulkan في المخزن المؤقت الحلقي</string>
|
<string name="gpu_log_vulkan_calls_description">تتبع جميع استدعاءات واجهة برمجة تطبيقات Vulkan في المخزن المؤقت الحلقي</string>
|
||||||
|
<string name="gpu_log_shader_dumps">تفريغ مظللات SPIR-V</string>
|
||||||
|
<string name="gpu_log_shader_dumps_description">احفظ ملفات SPIR-V الثنائية المُعاد تجميعها (.spv) في مجلد التفريغ. افحصها باستخدام spirv-dis/spirv-cross/spirv-val.</string>
|
||||||
|
<string name="dump_guest_shaders">تظليلات ضيف التفريغ (ماكسويل)</string>
|
||||||
|
<string name="dump_guest_shaders_description">احفظ ملفات بايت كود برنامج التظليل الضيف الخاص بـ «ماكسويل» (*.ash) في مجلد «dump». افحصها باستخدام nvdisasm.</string>
|
||||||
|
<string name="dump_macros">تفريغ ماكرو ماكسويل</string>
|
||||||
|
<string name="dump_macros_description">احفظ ملفات برامج ماكرو ماكسويل (*.macro) في مجلد «dump». افحصها باستخدام برنامج «envydis».</string>
|
||||||
<string name="gpu_log_memory_tracking">تتبع ذاكرة وحدة معالجة الرسومات</string>
|
<string name="gpu_log_memory_tracking">تتبع ذاكرة وحدة معالجة الرسومات</string>
|
||||||
<string name="gpu_log_memory_tracking_description">مراقبة تخصيصات ذاكرة وحدة معالجة الرسومات وإلغاء تخصيصها</string>
|
<string name="gpu_log_memory_tracking_description">مراقبة تخصيصات ذاكرة وحدة معالجة الرسومات وإلغاء تخصيصها</string>
|
||||||
<string name="gpu_log_driver_debug">معلومات تصحيح أخطاء برنامج التشغيل</string>
|
<string name="gpu_log_driver_debug">معلومات تصحيح أخطاء برنامج التشغيل</string>
|
||||||
@@ -1000,6 +1008,13 @@
|
|||||||
<string name="dma_accuracy_unsafe">غير آمن</string>
|
<string name="dma_accuracy_unsafe">غير آمن</string>
|
||||||
<string name="dma_accuracy_safe">آمن</string>
|
<string name="dma_accuracy_safe">آمن</string>
|
||||||
|
|
||||||
|
<!-- GPU Fence Behavior -->
|
||||||
|
<string name="gpu_fence_behavior_default">افتراضي</string>
|
||||||
|
<string name="gpu_fence_behavior_immediate">فوري</string>
|
||||||
|
<string name="gpu_fence_behavior_balanced">متوازن</string>
|
||||||
|
<string name="gpu_fence_behavior_accurate">دقيق</string>
|
||||||
|
<string name="gpu_fence_behavior_strict">صارم</string>
|
||||||
|
|
||||||
<string name="vram_usage_conservative">محافظ</string>
|
<string name="vram_usage_conservative">محافظ</string>
|
||||||
<string name="vram_usage_aggressive">عدواني</string>
|
<string name="vram_usage_aggressive">عدواني</string>
|
||||||
|
|
||||||
|
|||||||
@@ -470,6 +470,7 @@
|
|||||||
<string name="renderer_accuracy_description">Controla el modo de la emulación de la GPU. La mayoría de los juegos se renderizan correctamente en los modos Rápido o Equilibrado, pero algunos requieren Preciso. Las partículas tienden a renderizarse correctamente solo con el modo Preciso.</string>
|
<string name="renderer_accuracy_description">Controla el modo de la emulación de la GPU. La mayoría de los juegos se renderizan correctamente en los modos Rápido o Equilibrado, pero algunos requieren Preciso. Las partículas tienden a renderizarse correctamente solo con el modo Preciso.</string>
|
||||||
<string name="dma_accuracy">Precisión de DMA</string>
|
<string name="dma_accuracy">Precisión de DMA</string>
|
||||||
<string name="dma_accuracy_description">Controla la precisión de DMA. La precisión segura puede solucionar problemas en algunos juegos, pero también puede afectar al rendimiento en algunos casos. Si no está seguro, déjelo en Predeterminado.</string>
|
<string name="dma_accuracy_description">Controla la precisión de DMA. La precisión segura puede solucionar problemas en algunos juegos, pero también puede afectar al rendimiento en algunos casos. Si no está seguro, déjelo en Predeterminado.</string>
|
||||||
|
<string name="gpu_fence_behavior">Comportamiento de vallado de la GPU</string>
|
||||||
<string name="anisotropic_filtering">Filtrado anisotrópico</string>
|
<string name="anisotropic_filtering">Filtrado anisotrópico</string>
|
||||||
<string name="anisotropic_filtering_description">Mejora la calidad de las texturas al ser observadas desde ángulos oblicuos</string>
|
<string name="anisotropic_filtering_description">Mejora la calidad de las texturas al ser observadas desde ángulos oblicuos</string>
|
||||||
<string name="vram_usage_mode">Modo de uso de VRAM</string>
|
<string name="vram_usage_mode">Modo de uso de VRAM</string>
|
||||||
@@ -502,8 +503,6 @@
|
|||||||
<string name="fast_gpu_time_description">Fuerza a la mayoría de los juegos a ejecutarse a su resolución nativa más alta. Usa 256 para un máximo rendimiento y 512 para una fidelidad gráfica óptima.</string>
|
<string name="fast_gpu_time_description">Fuerza a la mayoría de los juegos a ejecutarse a su resolución nativa más alta. Usa 256 para un máximo rendimiento y 512 para una fidelidad gráfica óptima.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">Omitir invalidación interna de la CPU</string>
|
<string name="skip_cpu_inner_invalidation">Omitir invalidación interna de la CPU</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos.</string>
|
<string name="skip_cpu_inner_invalidation_description">Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos.</string>
|
||||||
<string name="antiflicker">Antiparpadeo</string>
|
|
||||||
<string name="antiflicker_description">Fuerza a las funciones de devolución de llamada de la GPU a esperar a que se envíen las tareas a la GPU.\nÚsalo con el modo de GPU rápida para evitar el parpadeo con un menor impacto en el rendimiento.</string>
|
|
||||||
<string name="fix_bloom_effects">Arreglar los efectos de resplandor</string>
|
<string name="fix_bloom_effects">Arreglar los efectos de resplandor</string>
|
||||||
<string name="fix_bloom_effects_description">Reduce el efecto de resplandor en LA/EOW (Adreno A6XX - A7XX/ Turnip), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos.</string>
|
<string name="fix_bloom_effects_description">Reduce el efecto de resplandor en LA/EOW (Adreno A6XX - A7XX/ Turnip), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos.</string>
|
||||||
<string name="emulate_bgr565">Emular BGR565</string>
|
<string name="emulate_bgr565">Emular BGR565</string>
|
||||||
@@ -1002,6 +1001,13 @@
|
|||||||
<string name="dma_accuracy_unsafe">Inseguro</string>
|
<string name="dma_accuracy_unsafe">Inseguro</string>
|
||||||
<string name="dma_accuracy_safe">Seguro</string>
|
<string name="dma_accuracy_safe">Seguro</string>
|
||||||
|
|
||||||
|
<!-- GPU Fence Behavior -->
|
||||||
|
<string name="gpu_fence_behavior_default">Predeterminado</string>
|
||||||
|
<string name="gpu_fence_behavior_immediate">Inmediato</string>
|
||||||
|
<string name="gpu_fence_behavior_balanced">Equilibrado</string>
|
||||||
|
<string name="gpu_fence_behavior_accurate">Preciso</string>
|
||||||
|
<string name="gpu_fence_behavior_strict">Estricto</string>
|
||||||
|
|
||||||
<string name="vram_usage_conservative">Conservador</string>
|
<string name="vram_usage_conservative">Conservador</string>
|
||||||
<string name="vram_usage_aggressive">Agresivo</string>
|
<string name="vram_usage_aggressive">Agresivo</string>
|
||||||
|
|
||||||
|
|||||||
@@ -499,8 +499,6 @@
|
|||||||
<string name="fast_gpu_time_description">Принудительно запускает большинство игр в их максимальном нативном разрешении. Используйте значение 256 для максимальной производительности и 512 для максимального качества графики.</string>
|
<string name="fast_gpu_time_description">Принудительно запускает большинство игр в их максимальном нативном разрешении. Используйте значение 256 для максимальной производительности и 512 для максимального качества графики.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
|
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
|
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
|
||||||
<string name="antiflicker">Анти-мерцание</string>
|
|
||||||
<string name="antiflicker_description">Принудительно заставляет обратные вызовы ГПУ-фильтра ожидать выполнения отправленных задач на ГПУ. Используйте с Быстрым режимом ГПУ, что бы избежать мерцаний с меньшим влиянием на производительность.</string>
|
|
||||||
<string name="fix_bloom_effects">Исправить эффекты размытия</string>
|
<string name="fix_bloom_effects">Исправить эффекты размытия</string>
|
||||||
<string name="fix_bloom_effects_description">Частично убирает размытие в LA/EOW (Adreno A6XX - A7XX/ Turnip), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх.</string>
|
<string name="fix_bloom_effects_description">Частично убирает размытие в LA/EOW (Adreno A6XX - A7XX/ Turnip), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх.</string>
|
||||||
<string name="emulate_bgr565">Эмулировать BGR565</string>
|
<string name="emulate_bgr565">Эмулировать BGR565</string>
|
||||||
|
|||||||
@@ -502,8 +502,6 @@
|
|||||||
<string name="fast_gpu_time_description">Примушує більшість ігор працювати на їхній максимальній нативній роздільності. Використовуйте 256 для максимальної продуктивності та 512 для найкращої якості.</string>
|
<string name="fast_gpu_time_description">Примушує більшість ігор працювати на їхній максимальній нативній роздільності. Використовуйте 256 для максимальної продуктивності та 512 для найкращої якості.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">Пропустити внутрішнє інвалідування CPU</string>
|
<string name="skip_cpu_inner_invalidation">Пропустити внутрішнє інвалідування CPU</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх.</string>
|
<string name="skip_cpu_inner_invalidation_description">Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх.</string>
|
||||||
<string name="antiflicker">Антимерехтіння</string>
|
|
||||||
<string name="antiflicker_description">Змушує механізм синхронізації чекати, доки ГП завершить подані завдання. Використовуйте з режимом ГП «Швидко», щоб уникнути мерехтіння з меншими втратами продуктивності.</string>
|
|
||||||
<string name="fix_bloom_effects">Виправити ефекти світіння</string>
|
<string name="fix_bloom_effects">Виправити ефекти світіння</string>
|
||||||
<string name="fix_bloom_effects_description">Зменшує розмиття світіння в LA/EOW (Adreno A6XX–A7XX / Turnip), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх.</string>
|
<string name="fix_bloom_effects_description">Зменшує розмиття світіння в LA/EOW (Adreno A6XX–A7XX / Turnip), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх.</string>
|
||||||
<string name="emulate_bgr565">Емулювати BGR565</string>
|
<string name="emulate_bgr565">Емулювати BGR565</string>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
<string name="show_shaders_building">显示着色器编译信息</string>
|
<string name="show_shaders_building">显示着色器编译信息</string>
|
||||||
<string name="show_shaders_building_description">显示当前正在编译的着色器数量</string>
|
<string name="show_shaders_building_description">显示当前正在编译的着色器数量</string>
|
||||||
<string name="pipeline_worker_cores">管线工作线程</string>
|
<string name="pipeline_worker_cores">管线工作线程</string>
|
||||||
<string name="pipeline_worker_cores_description">管理用于构建 Vulkan 管线的核心数量,数值越高则管线编译性能越好,但温度也会随之升高。</string>
|
<string name="pipeline_worker_cores_description">管理用于构建 Vulkan 管线的核心数量,较高的值可提升管线编译性能,但温度也会随之升高。</string>
|
||||||
<string name="overlay_position">叠加层位置</string>
|
<string name="overlay_position">叠加层位置</string>
|
||||||
<string name="overlay_position_description">选择叠加层在屏幕上显示的位置</string>
|
<string name="overlay_position_description">选择叠加层在屏幕上显示的位置</string>
|
||||||
<string name="overlay_position_top_left">左上</string>
|
<string name="overlay_position_top_left">左上</string>
|
||||||
@@ -185,7 +185,7 @@
|
|||||||
<string name="multiplayer_preferred_game_name">首选游戏</string>
|
<string name="multiplayer_preferred_game_name">首选游戏</string>
|
||||||
<string name="multiplayer_lobby_type">游戏大厅类型</string>
|
<string name="multiplayer_lobby_type">游戏大厅类型</string>
|
||||||
<string name="multiplayer_room_name_error">长度需为3-20个字符</string>
|
<string name="multiplayer_room_name_error">长度需为3-20个字符</string>
|
||||||
<string name="multiplayer_required">必填</string>
|
<string name="multiplayer_required">需要</string>
|
||||||
<string name="multiplayer_token_required">需要Web令牌,请前往高级设置 -> 系统 -> 网络</string>
|
<string name="multiplayer_token_required">需要Web令牌,请前往高级设置 -> 系统 -> 网络</string>
|
||||||
<string name="multiplayer_ip_error">IP格式无效</string>
|
<string name="multiplayer_ip_error">IP格式无效</string>
|
||||||
<string name="multiplayer_username_error">必须为4至20个字符,且仅包含字母、数字、点号、连字符、下划线和空格</string>
|
<string name="multiplayer_username_error">必须为4至20个字符,且仅包含字母、数字、点号、连字符、下划线和空格</string>
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
<string name="warning_skip">跳过</string>
|
<string name="warning_skip">跳过</string>
|
||||||
<string name="warning_cancel">取消</string>
|
<string name="warning_cancel">取消</string>
|
||||||
<string name="install_amiibo_keys">安装 Amiibo 密钥文件</string>
|
<string name="install_amiibo_keys">安装 Amiibo 密钥文件</string>
|
||||||
<string name="install_amiibo_keys_description">在遊戏中使用 Amiibo 时必需</string>
|
<string name="install_amiibo_keys_description">在遊戏中使用 Amiibo 时需要</string>
|
||||||
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
|
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
|
||||||
<string name="gpu_driver_manager">GPU 驱动管理器</string>
|
<string name="gpu_driver_manager">GPU 驱动管理器</string>
|
||||||
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
|
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
|
||||||
@@ -463,11 +463,13 @@
|
|||||||
<string name="advanced">高级</string>
|
<string name="advanced">高级</string>
|
||||||
|
|
||||||
<string name="renderer_accuracy">GPU 模式</string>
|
<string name="renderer_accuracy">GPU 模式</string>
|
||||||
<string name="renderer_accuracy_description">控制 GPU 模拟模式。大多数游戏在“快速”或“平衡”模式下都能正常渲染,但有些游戏仍需使用“精确”模式。粒子效果通常只有在“精确”模式下才能正确渲染。</string>
|
<string name="renderer_accuracy_description">控制 GPU 模拟模式。大多数游戏在“快速”或“均衡”模式下都能获得良好的渲染,但有些游戏仍需使用“精确”模式。粒子效果通常只有在“精确”模式下才能正确渲染。</string>
|
||||||
<string name="dma_accuracy">DMA 精度</string>
|
<string name="dma_accuracy">DMA 精度</string>
|
||||||
<string name="dma_accuracy_description">控制 DMA 的精准度。安全精度可以修复存在于某些游戏中的问题,但在某些情况下也会对性能造成影响。如不确定,请保持“默认”。</string>
|
<string name="dma_accuracy_description">控制 DMA 的精准度。安全精度可以修复存在于某些游戏中的问题,但在某些情况下也会对性能造成影响。如不确定,请保持“默认”。</string>
|
||||||
|
<string name="gpu_fence_behavior">GPU 围栏行为</string>
|
||||||
|
<string name="gpu_fence_behavior_description">控制 GPU 围栏同步行为。“即时”是速度最快的选项,但可能会引入一些问题。“均衡”提供了更好的兼容性,可能修复某些游戏中的问题。“精确”在牺牲部分性能的前提下进一步提升兼容性。“严格”是速度最慢的选项,但可以修复那些要求更严格同步的问题。默认遵循 GPU “精确”设定。</string>
|
||||||
<string name="anisotropic_filtering">各向异性过滤</string>
|
<string name="anisotropic_filtering">各向异性过滤</string>
|
||||||
<string name="anisotropic_filtering_description">提高斜角的纹理质量</string>
|
<string name="anisotropic_filtering_description">提升斜视角下的纹理质量</string>
|
||||||
<string name="vram_usage_mode">显存使用模式</string>
|
<string name="vram_usage_mode">显存使用模式</string>
|
||||||
<string name="vram_usage_mode_description">控制显存分配与释放策略</string>
|
<string name="vram_usage_mode_description">控制显存分配与释放策略</string>
|
||||||
<string name="accelerate_astc">ASTC解码方式</string>
|
<string name="accelerate_astc">ASTC解码方式</string>
|
||||||
@@ -488,7 +490,7 @@
|
|||||||
<string name="enable_buffer_history">启用缓冲区历史</string>
|
<string name="enable_buffer_history">启用缓冲区历史</string>
|
||||||
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
|
||||||
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
|
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
|
||||||
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏需要这样做才能正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
|
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏会用到这项设定以正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
|
||||||
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
|
||||||
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
|
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
|
||||||
|
|
||||||
@@ -498,8 +500,6 @@
|
|||||||
<string name="fast_gpu_time_description">强制大多数游戏以其最高原生分辨率运行。设置为 256 可获得最佳性能,设置为 512 可获得最佳画面保真度。</string>
|
<string name="fast_gpu_time_description">强制大多数游戏以其最高原生分辨率运行。设置为 256 可获得最佳性能,设置为 512 可获得最佳画面保真度。</string>
|
||||||
<string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string>
|
<string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。</string>
|
<string name="skip_cpu_inner_invalidation_description">在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。</string>
|
||||||
<string name="antiflicker">防闪烁</string>
|
|
||||||
<string name="antiflicker_description">强制 GPU 围栏回调等待已提交的 GPU 任务。配合“快速 GPU 模式”一起使用,以牺牲少量性能为代价来避免画面闪烁现象。</string>
|
|
||||||
<string name="fix_bloom_effects">修复 Bloom 效果</string>
|
<string name="fix_bloom_effects">修复 Bloom 效果</string>
|
||||||
<string name="fix_bloom_effects_description">减少《智慧的再现》和《众神的三角力量2》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。</string>
|
<string name="fix_bloom_effects_description">减少《智慧的再现》和《众神的三角力量2》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。</string>
|
||||||
<string name="emulate_bgr565">模拟 BGR565</string>
|
<string name="emulate_bgr565">模拟 BGR565</string>
|
||||||
@@ -513,7 +513,7 @@
|
|||||||
<string name="gpu_unswizzle_enable">启用 GPU Unswizzle</string>
|
<string name="gpu_unswizzle_enable">启用 GPU Unswizzle</string>
|
||||||
<string name="gpu_unswizzle_disabled">禁用</string>
|
<string name="gpu_unswizzle_disabled">禁用</string>
|
||||||
<string name="gpu_unswizzle_texture_size">GPU Unswizzle 最大纹理尺寸</string>
|
<string name="gpu_unswizzle_texture_size">GPU Unswizzle 最大纹理尺寸</string>
|
||||||
<string name="gpu_unswizzle_texture_size_description">设置基于 GPU 的纹理 unswizzling 的最大尺寸(MB)。虽然 GPU 处理中等和大型纹理的速度更快,但对于非常小的纹理,CPU 可能更为高效。通过调节此项设置,以尝试在 GPU 加速与 CPU 开销之间找到平衡。</string>
|
<string name="gpu_unswizzle_texture_size_description">设置基于 GPU 的纹理 unswizzling 的最大尺寸(MB)。虽然 GPU 处理中等和大型纹理的速度更快,但对于非常小的纹理,CPU 可能更为高效。通过调节此项设置,以平衡GPU 加速与 CPU 开销。</string>
|
||||||
<string name="gpu_unswizzle_stream_size">GPU Unswizzle 流大小</string>
|
<string name="gpu_unswizzle_stream_size">GPU Unswizzle 流大小</string>
|
||||||
<string name="gpu_unswizzle_stream_size_description">设置用于 unswizzling 大型纹理时的每帧数据限制。较高的数值可以加速纹理的加载过程,但会带来更高的帧延迟。而较低的数值则可以降低 GPU 的开销,但也可能会导致可见的纹理闪现。</string>
|
<string name="gpu_unswizzle_stream_size_description">设置用于 unswizzling 大型纹理时的每帧数据限制。较高的数值可以加速纹理的加载过程,但会带来更高的帧延迟。而较低的数值则可以降低 GPU 的开销,但也可能会导致可见的纹理闪现。</string>
|
||||||
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle 块大小</string>
|
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle 块大小</string>
|
||||||
@@ -990,7 +990,7 @@
|
|||||||
|
|
||||||
<!-- Renderer Accuracy -->
|
<!-- Renderer Accuracy -->
|
||||||
<string name="renderer_accuracy_low">快速</string>
|
<string name="renderer_accuracy_low">快速</string>
|
||||||
<string name="renderer_accuracy_medium">平衡</string>
|
<string name="renderer_accuracy_medium">均衡</string>
|
||||||
<string name="renderer_accuracy_high">精确</string>
|
<string name="renderer_accuracy_high">精确</string>
|
||||||
|
|
||||||
<!-- DMA Accuracy -->
|
<!-- DMA Accuracy -->
|
||||||
@@ -998,6 +998,13 @@
|
|||||||
<string name="dma_accuracy_unsafe">不安全</string>
|
<string name="dma_accuracy_unsafe">不安全</string>
|
||||||
<string name="dma_accuracy_safe">安全</string>
|
<string name="dma_accuracy_safe">安全</string>
|
||||||
|
|
||||||
|
<!-- GPU Fence Behavior -->
|
||||||
|
<string name="gpu_fence_behavior_default">默认</string>
|
||||||
|
<string name="gpu_fence_behavior_immediate">即时</string>
|
||||||
|
<string name="gpu_fence_behavior_balanced">均衡</string>
|
||||||
|
<string name="gpu_fence_behavior_accurate">精确</string>
|
||||||
|
<string name="gpu_fence_behavior_strict">严格</string>
|
||||||
|
|
||||||
<string name="vram_usage_conservative">保守式</string>
|
<string name="vram_usage_conservative">保守式</string>
|
||||||
<string name="vram_usage_aggressive">主动式</string>
|
<string name="vram_usage_aggressive">主动式</string>
|
||||||
|
|
||||||
@@ -1021,7 +1028,7 @@
|
|||||||
<string name="ratio_stretch">拉伸窗口</string>
|
<string name="ratio_stretch">拉伸窗口</string>
|
||||||
|
|
||||||
<!-- CPU Accuracy -->
|
<!-- CPU Accuracy -->
|
||||||
<string name="cpu_accuracy_accurate">精准</string>
|
<string name="cpu_accuracy_accurate">精确</string>
|
||||||
<string name="cpu_accuracy_unsafe">不安全</string>
|
<string name="cpu_accuracy_unsafe">不安全</string>
|
||||||
<string name="cpu_accuracy_paranoid">极致</string>
|
<string name="cpu_accuracy_paranoid">极致</string>
|
||||||
<string name="cpu_accuracy_debugging">调试</string>
|
<string name="cpu_accuracy_debugging">调试</string>
|
||||||
|
|||||||
@@ -522,6 +522,21 @@
|
|||||||
<item>2</item>
|
<item>2</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
<string-array name="gpuFenceBehaviorNames">
|
||||||
|
<item>@string/gpu_fence_behavior_default</item>
|
||||||
|
<item>@string/gpu_fence_behavior_immediate</item>
|
||||||
|
<item>@string/gpu_fence_behavior_balanced</item>
|
||||||
|
<item>@string/gpu_fence_behavior_accurate</item>
|
||||||
|
<item>@string/gpu_fence_behavior_strict</item>
|
||||||
|
</string-array>
|
||||||
|
<integer-array name="gpuFenceBehaviorValues">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
<item>4</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
|
|
||||||
<string-array name="appletEntries">
|
<string-array name="appletEntries">
|
||||||
<item>@string/applet_hle</item>
|
<item>@string/applet_hle</item>
|
||||||
|
|||||||
@@ -482,6 +482,8 @@
|
|||||||
<string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string>
|
<string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string>
|
||||||
<string name="dma_accuracy">DMA Accuracy</string>
|
<string name="dma_accuracy">DMA Accuracy</string>
|
||||||
<string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string>
|
<string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string>
|
||||||
|
<string name="gpu_fence_behavior">GPU Fence Behavior</string>
|
||||||
|
<string name="gpu_fence_behavior_description">Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. Accurate further improves compatibility at the cost of some performance. Strict is the slowest option, but can fix issues that require stricter synchronization. Default follows the GPU Accuracy setting.</string>
|
||||||
<string name="anisotropic_filtering">Anisotropic filtering</string>
|
<string name="anisotropic_filtering">Anisotropic filtering</string>
|
||||||
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
|
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
|
||||||
<string name="vram_usage_mode">VRAM Usage Mode</string>
|
<string name="vram_usage_mode">VRAM Usage Mode</string>
|
||||||
@@ -514,8 +516,6 @@
|
|||||||
<string name="fast_gpu_time_description">Forces most games to run at their highest native resolution. Use 256 for maximal performance and 512 for maximal graphics fidelity.</string>
|
<string name="fast_gpu_time_description">Forces most games to run at their highest native resolution. Use 256 for maximal performance and 512 for maximal graphics fidelity.</string>
|
||||||
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
||||||
<string name="antiflicker">Anti-Flicker</string>
|
|
||||||
<string name="antiflicker_description">Forces GPU fence callbacks to wait for submitted GPU work. Use with Fast GPU mode, to avoid flicker with lower performance impact.</string>
|
|
||||||
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
||||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||||
<string name="emulate_bgr565">Emulate BGR565</string>
|
<string name="emulate_bgr565">Emulate BGR565</string>
|
||||||
@@ -1047,6 +1047,13 @@
|
|||||||
<string name="dma_accuracy_unsafe">Unsafe</string>
|
<string name="dma_accuracy_unsafe">Unsafe</string>
|
||||||
<string name="dma_accuracy_safe">Safe</string>
|
<string name="dma_accuracy_safe">Safe</string>
|
||||||
|
|
||||||
|
<!-- GPU Fence Behavior -->
|
||||||
|
<string name="gpu_fence_behavior_default">Default</string>
|
||||||
|
<string name="gpu_fence_behavior_immediate">Immediate</string>
|
||||||
|
<string name="gpu_fence_behavior_balanced">Balanced</string>
|
||||||
|
<string name="gpu_fence_behavior_accurate">Accurate</string>
|
||||||
|
<string name="gpu_fence_behavior_strict">Strict</string>
|
||||||
|
|
||||||
<!-- ASTC Decoding Method Choices -->
|
<!-- ASTC Decoding Method Choices -->
|
||||||
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
||||||
<string name="accelerate_astc_gpu" translatable="false">GPU</string>
|
<string name="accelerate_astc_gpu" translatable="false">GPU</string>
|
||||||
|
|||||||
+16
-8
@@ -156,14 +156,6 @@ void UpdateGPUAccuracy() {
|
|||||||
values.current_gpu_accuracy = values.gpu_accuracy.GetValue();
|
values.current_gpu_accuracy = values.gpu_accuracy.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsGPULevelLow() {
|
|
||||||
return values.current_gpu_accuracy == GpuAccuracy::Low;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsGPULevelMedium() {
|
|
||||||
return values.current_gpu_accuracy == GpuAccuracy::Medium;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsGPULevelHigh() {
|
bool IsGPULevelHigh() {
|
||||||
return values.current_gpu_accuracy == GpuAccuracy::High;
|
return values.current_gpu_accuracy == GpuAccuracy::High;
|
||||||
}
|
}
|
||||||
@@ -176,6 +168,22 @@ bool IsDMALevelSafe() {
|
|||||||
return values.dma_accuracy.GetValue() == DmaAccuracy::Safe;
|
return values.dma_accuracy.GetValue() == DmaAccuracy::Safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsGPUFenceBehaviorDefault() {
|
||||||
|
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsGPUFenceBehaviorBalanced() {
|
||||||
|
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Balanced;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsGPUFenceBehaviorAccurate() {
|
||||||
|
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsGPUFenceBehaviorStrict() {
|
||||||
|
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Strict;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsFastmemEnabled() {
|
bool IsFastmemEnabled() {
|
||||||
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
|
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
|
||||||
return bool(values.cpuopt_fastmem);
|
return bool(values.cpuopt_fastmem);
|
||||||
|
|||||||
+17
-11
@@ -420,7 +420,7 @@ struct Values {
|
|||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
GpuAccuracy::Low,
|
GpuAccuracy::Low,
|
||||||
#else
|
#else
|
||||||
GpuAccuracy::Medium,
|
GpuAccuracy::High,
|
||||||
#endif
|
#endif
|
||||||
"gpu_accuracy",
|
"gpu_accuracy",
|
||||||
Category::RendererAdvanced,
|
Category::RendererAdvanced,
|
||||||
@@ -428,7 +428,7 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
|
||||||
GpuAccuracy current_gpu_accuracy{GpuAccuracy::Medium};
|
GpuAccuracy current_gpu_accuracy{GpuAccuracy::High};
|
||||||
|
|
||||||
SwitchableSetting<DmaAccuracy, true> dma_accuracy{linkage,
|
SwitchableSetting<DmaAccuracy, true> dma_accuracy{linkage,
|
||||||
DmaAccuracy::Default,
|
DmaAccuracy::Default,
|
||||||
@@ -438,6 +438,16 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
|
||||||
|
SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage,
|
||||||
|
GpuFenceBehavior::Default,
|
||||||
|
GpuFenceBehavior::Default,
|
||||||
|
GpuFenceBehavior::Strict,
|
||||||
|
"gpu_fence_behavior",
|
||||||
|
Category::RendererAdvanced,
|
||||||
|
Specialization::Default,
|
||||||
|
true,
|
||||||
|
true};
|
||||||
|
|
||||||
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
||||||
VramUsageMode::Conservative,
|
VramUsageMode::Conservative,
|
||||||
"vram_usage_mode",
|
"vram_usage_mode",
|
||||||
@@ -545,13 +555,6 @@ struct Values {
|
|||||||
Specialization::Default,
|
Specialization::Default,
|
||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
SwitchableSetting<bool> antiflicker{linkage,
|
|
||||||
false,
|
|
||||||
"antiflicker",
|
|
||||||
Category::RendererHacks,
|
|
||||||
Specialization::Default,
|
|
||||||
true,
|
|
||||||
true};
|
|
||||||
SwitchableSetting<bool> async_presentation{linkage,
|
SwitchableSetting<bool> async_presentation{linkage,
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
false,
|
false,
|
||||||
@@ -871,13 +874,16 @@ extern Values values;
|
|||||||
bool getDebugKnobAt(u8 i);
|
bool getDebugKnobAt(u8 i);
|
||||||
|
|
||||||
void UpdateGPUAccuracy();
|
void UpdateGPUAccuracy();
|
||||||
bool IsGPULevelLow();
|
|
||||||
bool IsGPULevelMedium();
|
|
||||||
bool IsGPULevelHigh();
|
bool IsGPULevelHigh();
|
||||||
|
|
||||||
bool IsDMALevelDefault();
|
bool IsDMALevelDefault();
|
||||||
bool IsDMALevelSafe();
|
bool IsDMALevelSafe();
|
||||||
|
|
||||||
|
bool IsGPUFenceBehaviorDefault();
|
||||||
|
bool IsGPUFenceBehaviorBalanced();
|
||||||
|
bool IsGPUFenceBehaviorAccurate();
|
||||||
|
bool IsGPUFenceBehaviorStrict();
|
||||||
|
|
||||||
bool IsFastmemEnabled();
|
bool IsFastmemEnabled();
|
||||||
void SetNceEnabled(bool is_64bit);
|
void SetNceEnabled(bool is_64bit);
|
||||||
bool IsNceEnabled();
|
bool IsNceEnabled();
|
||||||
|
|||||||
@@ -135,8 +135,9 @@ ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
|
|||||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||||
ENUM(GpuAccuracy, Low, Medium, High);
|
ENUM(GpuAccuracy, Low, High);
|
||||||
ENUM(DmaAccuracy, Default, Unsafe, Safe);
|
ENUM(DmaAccuracy, Default, Unsafe, Safe);
|
||||||
|
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate, Strict);
|
||||||
ENUM(CpuBackend, Dynarmic, Nce);
|
ENUM(CpuBackend, Dynarmic, Nce);
|
||||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
|
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
|
||||||
ENUM(CpuClock, Off, Boost, Fast)
|
ENUM(CpuClock, Off, Boost, Fast)
|
||||||
|
|||||||
@@ -157,6 +157,8 @@ bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info,
|
|||||||
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
|
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr size_t NCE_WRITE_FAULT_CLUSTER_PAGES = 4;
|
||||||
|
|
||||||
bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
|
bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
|
||||||
auto* info = static_cast<siginfo_t*>(raw_info);
|
auto* info = static_cast<siginfo_t*>(raw_info);
|
||||||
|
|
||||||
@@ -165,7 +167,7 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi
|
|||||||
const Common::ProcessAddress addr =
|
const Common::ProcessAddress addr =
|
||||||
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
||||||
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
|
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
|
||||||
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
|
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE * NCE_WRITE_FAULT_CLUSTER_PAGES)) {
|
||||||
// We handled the access successfully and are returning to guest code.
|
// We handled the access successfully and are returning to guest code.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ public:
|
|||||||
// New batch API to update multiple ranges with a single lock acquisition.
|
// New batch API to update multiple ranges with a single lock acquisition.
|
||||||
void UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta);
|
void UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta);
|
||||||
|
|
||||||
|
void UpdateTexturePagesCount(DAddr addr, size_t size, s32 delta);
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsRegionTextureCached(DAddr addr, size_t size) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct TranslationEntry {
|
struct TranslationEntry {
|
||||||
DAddr guest_page{};
|
DAddr guest_page{};
|
||||||
@@ -234,6 +238,7 @@ private:
|
|||||||
(1ULL << (device_virtual_bits - page_bits)) / subentries;
|
(1ULL << (device_virtual_bits - page_bits)) / subentries;
|
||||||
using CachedPages = std::array<CounterEntry, num_counter_entries>;
|
using CachedPages = std::array<CounterEntry, num_counter_entries>;
|
||||||
std::unique_ptr<CachedPages> cached_pages;
|
std::unique_ptr<CachedPages> cached_pages;
|
||||||
|
std::unique_ptr<CachedPages> texture_cached_pages;
|
||||||
Common::RangeMutex counter_guard;
|
Common::RangeMutex counter_guard;
|
||||||
std::mutex mapping_guard;
|
std::mutex mapping_guard;
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memo
|
|||||||
{
|
{
|
||||||
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
|
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
|
||||||
cached_pages = std::make_unique<CachedPages>();
|
cached_pages = std::make_unique<CachedPages>();
|
||||||
|
texture_cached_pages = std::make_unique<CachedPages>();
|
||||||
|
|
||||||
const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
|
const size_t total_virtual = device_as_size >> Memory::YUZU_PAGEBITS;
|
||||||
for (size_t i = 0; i < total_virtual; i++) {
|
for (size_t i = 0; i < total_virtual; i++) {
|
||||||
@@ -625,6 +626,28 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
|
|||||||
UpdatePagesCachedCountNoLock(addr, size, delta);
|
UpdatePagesCachedCountNoLock(addr, size, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
void DeviceMemoryManager<Traits>::UpdateTexturePagesCount(DAddr addr, size_t size, s32 delta) {
|
||||||
|
Common::ScopedRangeLock lk(counter_guard, addr, size);
|
||||||
|
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
|
||||||
|
for (size_t page = addr >> Memory::YUZU_PAGEBITS; page != page_end; ++page) {
|
||||||
|
CounterAtomicType& count = texture_cached_pages->at(page >> subentries_shift).Count(page);
|
||||||
|
count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
bool DeviceMemoryManager<Traits>::IsRegionTextureCached(DAddr addr, size_t size) const noexcept {
|
||||||
|
const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
|
||||||
|
for (size_t page = addr >> Memory::YUZU_PAGEBITS; page != page_end; ++page) {
|
||||||
|
if (texture_cached_pages->at(page >> subentries_shift).Count(page).load(
|
||||||
|
std::memory_order_acquire) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta) {
|
void DeviceMemoryManager<Traits>::UpdatePagesCachedBatch(std::span<const std::pair<DAddr, size_t>> ranges, s32 delta) {
|
||||||
if (ranges.empty()) {
|
if (ranges.empty()) {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ProgramMetadata::Is64BitProgram() const {
|
bool ProgramMetadata::Is64BitProgram() const {
|
||||||
return npdm_header.has_64_bit_instructions;
|
return bool(npdm_header.has_64_bit_instructions);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {
|
ProgramAddressSpaceType ProgramMetadata::GetAddressSpaceType() const {
|
||||||
|
|||||||
@@ -1662,17 +1662,17 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
|||||||
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
||||||
const auto type = is_configuring.load() && use_temporary_value ? tmp_npad_type.load() : npad_type.load();
|
const auto type = is_configuring.load() && use_temporary_value ? tmp_npad_type.load() : npad_type.load();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NpadStyleIndex::Fullkey: return supported_style_tag.fullkey;
|
case NpadStyleIndex::Fullkey: return bool(supported_style_tag.fullkey);
|
||||||
case NpadStyleIndex::Handheld: return supported_style_tag.handheld;
|
case NpadStyleIndex::Handheld: return bool(supported_style_tag.handheld);
|
||||||
case NpadStyleIndex::JoyconDual: return supported_style_tag.joycon_dual;
|
case NpadStyleIndex::JoyconDual: return bool(supported_style_tag.joycon_dual);
|
||||||
case NpadStyleIndex::JoyconLeft: return supported_style_tag.joycon_left;
|
case NpadStyleIndex::JoyconLeft: return bool(supported_style_tag.joycon_left);
|
||||||
case NpadStyleIndex::JoyconRight: return supported_style_tag.joycon_right;
|
case NpadStyleIndex::JoyconRight: return bool(supported_style_tag.joycon_right);
|
||||||
case NpadStyleIndex::GameCube: return supported_style_tag.gamecube;
|
case NpadStyleIndex::GameCube: return bool(supported_style_tag.gamecube);
|
||||||
case NpadStyleIndex::Pokeball: return supported_style_tag.palma;
|
case NpadStyleIndex::Pokeball: return bool(supported_style_tag.palma);
|
||||||
case NpadStyleIndex::NES: return supported_style_tag.lark;
|
case NpadStyleIndex::NES: return bool(supported_style_tag.lark);
|
||||||
case NpadStyleIndex::SNES: return supported_style_tag.lucia;
|
case NpadStyleIndex::SNES: return bool(supported_style_tag.lucia);
|
||||||
case NpadStyleIndex::N64: return supported_style_tag.lagoon;
|
case NpadStyleIndex::N64: return bool(supported_style_tag.lagoon);
|
||||||
case NpadStyleIndex::SegaGenesis: return supported_style_tag.lager;
|
case NpadStyleIndex::SegaGenesis: return bool(supported_style_tag.lager);
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ Result NpadAbstractSixAxisHandler::UpdateSixAxisState() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
||||||
UpdateSixaxisInternalState(npad_entry, data->aruid, data->flag.enable_six_axis_sensor);
|
UpdateSixaxisInternalState(npad_entry, data->aruid, bool(data->flag.enable_six_axis_sensor));
|
||||||
}
|
}
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ Result NpadAbstractSixAxisHandler::UpdateSixAxisState(u64 aruid) {
|
|||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
||||||
UpdateSixaxisInternalState(npad_entry, data->aruid, data->flag.enable_six_axis_sensor);
|
UpdateSixaxisInternalState(npad_entry, data->aruid, bool(data->flag.enable_six_axis_sensor));
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ Result NpadAbstractSixAxisHandler::UpdateSixAxisState2(u64 aruid) {
|
|||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
auto& npad_internal_state = aruid_data->shared_memory_format->npad.npad_entry[npad_index];
|
auto& npad_internal_state = aruid_data->shared_memory_format->npad.npad_entry[npad_index];
|
||||||
UpdateSixaxisInternalState(npad_internal_state, aruid, aruid_data->flag.enable_six_axis_sensor);
|
UpdateSixaxisInternalState(npad_internal_state, aruid, bool(aruid_data->flag.enable_six_axis_sensor));
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ void NPadData::SetNpadAnalogStickUseCenterClamp(bool is_enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool NPadData::GetNpadAnalogStickUseCenterClamp() const {
|
bool NPadData::GetNpadAnalogStickUseCenterClamp() const {
|
||||||
return status.use_center_clamp;
|
return bool(status.use_center_clamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPadData::SetNpadSystemExtStateEnabled(bool is_enabled) {
|
void NPadData::SetNpadSystemExtStateEnabled(bool is_enabled) {
|
||||||
@@ -32,7 +32,7 @@ void NPadData::SetNpadSystemExtStateEnabled(bool is_enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool NPadData::GetNpadSystemExtState() const {
|
bool NPadData::GetNpadSystemExtState() const {
|
||||||
return status.system_ext_state;
|
return bool(status.system_ext_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result NPadData::SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list) {
|
Result NPadData::SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> list) {
|
||||||
@@ -42,18 +42,14 @@ Result NPadData::SetSupportedNpadIdType(std::span<const Core::HID::NpadIdType> l
|
|||||||
}
|
}
|
||||||
|
|
||||||
supported_npad_id_types_count = list.size();
|
supported_npad_id_types_count = list.size();
|
||||||
memcpy(supported_npad_id_types.data(), list.data(),
|
std::memcpy(supported_npad_id_types.data(), list.data(), list.size() * sizeof(Core::HID::NpadIdType));
|
||||||
list.size() * sizeof(Core::HID::NpadIdType));
|
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t NPadData::GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const {
|
std::size_t NPadData::GetSupportedNpadIdType(std::span<Core::HID::NpadIdType> out_list) const {
|
||||||
std::size_t out_size = (std::min)(supported_npad_id_types_count, out_list.size());
|
std::size_t out_size = (std::min)(supported_npad_id_types_count, out_list.size());
|
||||||
|
|
||||||
memcpy(out_list.data(), supported_npad_id_types.data(),
|
std::memcpy(out_list.data(), supported_npad_id_types.data(), out_size * sizeof(Core::HID::NpadIdType));
|
||||||
out_size * sizeof(Core::HID::NpadIdType));
|
|
||||||
|
|
||||||
return out_size;
|
return out_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,27 +150,27 @@ bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index)
|
|||||||
Core::HID::NpadStyleTag style = {supported_npad_style_set};
|
Core::HID::NpadStyleTag style = {supported_npad_style_set};
|
||||||
switch (style_index) {
|
switch (style_index) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::Fullkey:
|
||||||
return style.fullkey;
|
return bool(style.fullkey);
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
return style.handheld;
|
return bool(style.handheld);
|
||||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||||
return style.joycon_dual;
|
return bool(style.joycon_dual);
|
||||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||||
return style.joycon_left;
|
return bool(style.joycon_left);
|
||||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||||
return style.joycon_right;
|
return bool(style.joycon_right);
|
||||||
case Core::HID::NpadStyleIndex::GameCube:
|
case Core::HID::NpadStyleIndex::GameCube:
|
||||||
return style.gamecube;
|
return bool(style.gamecube);
|
||||||
case Core::HID::NpadStyleIndex::Pokeball:
|
case Core::HID::NpadStyleIndex::Pokeball:
|
||||||
return style.palma;
|
return bool(style.palma);
|
||||||
case Core::HID::NpadStyleIndex::NES:
|
case Core::HID::NpadStyleIndex::NES:
|
||||||
return style.lark;
|
return bool(style.lark);
|
||||||
case Core::HID::NpadStyleIndex::SNES:
|
case Core::HID::NpadStyleIndex::SNES:
|
||||||
return style.lucia;
|
return bool(style.lucia);
|
||||||
case Core::HID::NpadStyleIndex::N64:
|
case Core::HID::NpadStyleIndex::N64:
|
||||||
return style.lagoon;
|
return bool(style.lagoon);
|
||||||
case Core::HID::NpadStyleIndex::SegaGenesis:
|
case Core::HID::NpadStyleIndex::SegaGenesis:
|
||||||
return style.lager;
|
return bool(style.lager);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -185,7 +181,7 @@ void NPadData::SetLrAssignmentMode(bool is_enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool NPadData::GetLrAssignmentMode() const {
|
bool NPadData::GetLrAssignmentMode() const {
|
||||||
return status.lr_assignment_mode;
|
return bool(status.lr_assignment_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPadData::SetAssigningSingleOnSlSrPress(bool is_enabled) {
|
void NPadData::SetAssigningSingleOnSlSrPress(bool is_enabled) {
|
||||||
@@ -193,7 +189,7 @@ void NPadData::SetAssigningSingleOnSlSrPress(bool is_enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool NPadData::GetAssigningSingleOnSlSrPress() const {
|
bool NPadData::GetAssigningSingleOnSlSrPress() const {
|
||||||
return status.assigning_single_on_sl_sr_press;
|
return bool(status.assigning_single_on_sl_sr_press);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPadData::SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id) {
|
void NPadData::SetHomeProtectionEnabled(bool is_enabled, Core::HID::NpadIdType npad_id) {
|
||||||
|
|||||||
@@ -548,7 +548,7 @@ void TouchResource::OnTouchUpdate(s64 timestamp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& touch_shared = applet_data->shared_memory_format->touch_screen;
|
auto& touch_shared = applet_data->shared_memory_format->touch_screen;
|
||||||
StorePreviousTouchState(previous_touch_state, data.finger_map, current_touch_state, applet_data->flag.enable_touchscreen);
|
StorePreviousTouchState(previous_touch_state, data.finger_map, current_touch_state, bool(applet_data->flag.enable_touchscreen));
|
||||||
touch_shared.touch_screen_lifo.WriteNextEntry(current_touch_state);
|
touch_shared.touch_screen_lifo.WriteNextEntry(current_touch_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,9 +193,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
|||||||
INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"),
|
INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"),
|
||||||
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
|
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
|
||||||
"improving latency. This may cause soft-crashes."));
|
"improving latency. This may cause soft-crashes."));
|
||||||
INSERT(Settings, antiflicker, tr("Anti-Flicker"),
|
|
||||||
tr("Forces GPU fence callbacks to wait for submitted GPU work.\n"
|
|
||||||
"Use with Fast GPU mode, to avoid flicker with lower performance impact."));
|
|
||||||
INSERT(Settings, vsync_mode, tr("VSync Mode:"),
|
INSERT(Settings, vsync_mode, tr("VSync Mode:"),
|
||||||
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||||
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
|
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
|
||||||
@@ -223,14 +220,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
|||||||
tr("Controls the quality of texture rendering at oblique angles.\nSafe to set at 16x on "
|
tr("Controls the quality of texture rendering at oblique angles.\nSafe to set at 16x on "
|
||||||
"most GPUs."));
|
"most GPUs."));
|
||||||
INSERT(Settings, gpu_accuracy, tr("GPU Mode:"),
|
INSERT(Settings, gpu_accuracy, tr("GPU Mode:"),
|
||||||
tr("Controls the GPU emulation mode.\nMost games render fine with Fast or Balanced "
|
tr("Controls the GPU emulation mode.\nMost games render fine with Fast, but Accurate is still "
|
||||||
"modes, but Accurate is still "
|
|
||||||
"required for some.\nParticles tend to only render correctly with Accurate mode."));
|
"required for some.\nParticles tend to only render correctly with Accurate mode."));
|
||||||
INSERT(Settings, dma_accuracy, tr("DMA Accuracy:"),
|
INSERT(Settings, dma_accuracy, tr("DMA Accuracy:"),
|
||||||
tr("Controls the DMA precision accuracy. Safe precision fixes issues in some games but "
|
tr("Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting."));
|
||||||
"may degrade performance."));
|
INSERT(Settings, gpu_fence_behavior, tr("GPU Fence Behavior:"),
|
||||||
|
tr("Controls the GPU fence synchronization behavior.\nImmediate is the fastest option, but can introduce some issues.\nBalanced offers better compatibility and may fix issues in some games.\nAccurate further improves compatibility at the cost of some performance.\nStrict is the slowest option, but can fix issues that require stricter synchronization.\nDefault follows the GPU Accuracy setting."));
|
||||||
INSERT(Settings, enable_gpu_buffer_readback, tr("Enable GPU buffer readback"),
|
INSERT(Settings, enable_gpu_buffer_readback, tr("Enable GPU buffer readback"),
|
||||||
tr("Preserves GPU-modified buffer data by reading it back before uploads.\nSome games require this to render certain effects properly.\nMay cause issues if the hardware cannot handle the additional workload."));
|
tr("Preserves GPU-modified data by reading it back before uploading.\nSome games require this to render certain effects properly."));
|
||||||
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
|
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
|
||||||
tr("May reduce shader stutter."));
|
tr("May reduce shader stutter."));
|
||||||
INSERT(Settings, fast_gpu_time, tr("Fast GPU Time"),
|
INSERT(Settings, fast_gpu_time, tr("Fast GPU Time"),
|
||||||
@@ -430,7 +427,6 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
|
|||||||
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
|
||||||
{
|
{
|
||||||
PAIR(GpuAccuracy, Low, tr("Fast")),
|
PAIR(GpuAccuracy, Low, tr("Fast")),
|
||||||
PAIR(GpuAccuracy, Medium, tr("Balanced")),
|
|
||||||
PAIR(GpuAccuracy, High, tr("Accurate")),
|
PAIR(GpuAccuracy, High, tr("Accurate")),
|
||||||
}});
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::DmaAccuracy>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::DmaAccuracy>::Index(),
|
||||||
@@ -439,6 +435,14 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
|
|||||||
PAIR(DmaAccuracy, Unsafe, tr("Unsafe (fast)")),
|
PAIR(DmaAccuracy, Unsafe, tr("Unsafe (fast)")),
|
||||||
PAIR(DmaAccuracy, Safe, tr("Safe (stable)")),
|
PAIR(DmaAccuracy, Safe, tr("Safe (stable)")),
|
||||||
}});
|
}});
|
||||||
|
translations->insert({Settings::EnumMetadata<Settings::GpuFenceBehavior>::Index(),
|
||||||
|
{
|
||||||
|
PAIR(GpuFenceBehavior, Default, tr("Default")),
|
||||||
|
PAIR(GpuFenceBehavior, Immediate, tr("Immediate")),
|
||||||
|
PAIR(GpuFenceBehavior, Balanced, tr("Balanced")),
|
||||||
|
PAIR(GpuFenceBehavior, Accurate, tr("Accurate")),
|
||||||
|
PAIR(GpuFenceBehavior, Strict, tr("Strict")),
|
||||||
|
}});
|
||||||
translations->insert(
|
translations->insert(
|
||||||
{Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
|
{Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map
|
|||||||
|
|
||||||
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
|
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
|
||||||
{Settings::GpuAccuracy::Low, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Fast"))},
|
{Settings::GpuAccuracy::Low, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Fast"))},
|
||||||
{Settings::GpuAccuracy::Medium, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Balanced"))},
|
|
||||||
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Accurate"))},
|
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Accurate"))},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -223,9 +223,6 @@ struct Values {
|
|||||||
// perf overlay
|
// perf overlay
|
||||||
Setting<bool> show_perf_overlay{linkage, false, "show_perf_overlay", Category::UiGameList};
|
Setting<bool> show_perf_overlay{linkage, false, "show_perf_overlay", Category::UiGameList};
|
||||||
|
|
||||||
// Compatibility List
|
|
||||||
Setting<bool> show_compat{linkage, true, "show_compat", Category::UiGameList};
|
|
||||||
|
|
||||||
// Size & File Types Column
|
// Size & File Types Column
|
||||||
Setting<bool> show_size{linkage, true, "show_size", Category::UiGameList};
|
Setting<bool> show_size{linkage, true, "show_size", Category::UiGameList};
|
||||||
Setting<bool> show_types{linkage, true, "show_types", Category::UiGameList};
|
Setting<bool> show_types{linkage, true, "show_types", Category::UiGameList};
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ void GameListModel::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
|
|||||||
current_worker.reset();
|
current_worker.reset();
|
||||||
removeRows(0, rowCount());
|
removeRows(0, rowCount());
|
||||||
|
|
||||||
current_worker = std::make_unique<GameListWorker>(vfs, provider, game_dirs, compatibility_list,
|
current_worker = std::make_unique<GameListWorker>(vfs, provider, game_dirs,
|
||||||
play_time_manager, system);
|
play_time_manager, system);
|
||||||
|
|
||||||
connect(current_worker.get(), &GameListWorker::DataAvailable, this, &GameListModel::WorkerEvent,
|
connect(current_worker.get(), &GameListWorker::DataAvailable, this, &GameListModel::WorkerEvent,
|
||||||
@@ -157,50 +157,6 @@ void GameListModel::RemoveFavorite(u64 program_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameListModel::LoadCompatibilityList() {
|
|
||||||
QFile compat_list{QStringLiteral(":compatibility_list/compatibility_list.json")};
|
|
||||||
|
|
||||||
if (!compat_list.open(QFile::ReadOnly | QFile::Text)) {
|
|
||||||
LOG_ERROR(Frontend, "Unable to open game compatibility list");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compat_list.size() == 0) {
|
|
||||||
LOG_WARNING(Frontend, "Game compatibility list is empty");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray content = compat_list.readAll();
|
|
||||||
if (content.isEmpty()) {
|
|
||||||
LOG_ERROR(Frontend, "Unable to completely read game compatibility list");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QJsonDocument json = QJsonDocument::fromJson(content);
|
|
||||||
const QJsonArray arr = json.array();
|
|
||||||
|
|
||||||
for (const QJsonValue& value : arr) {
|
|
||||||
const QJsonObject game = value.toObject();
|
|
||||||
const QString compatibility_key = QStringLiteral("compatibility");
|
|
||||||
|
|
||||||
if (!game.contains(compatibility_key) || !game[compatibility_key].isDouble()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int compatibility = game[compatibility_key].toInt();
|
|
||||||
const QString directory = game[QStringLiteral("directory")].toString();
|
|
||||||
const QJsonArray ids = game[QStringLiteral("releases")].toArray();
|
|
||||||
|
|
||||||
for (const QJsonValue& id_ref : ids) {
|
|
||||||
const QJsonObject id_object = id_ref.toObject();
|
|
||||||
const QString id = id_object[QStringLiteral("id")].toString();
|
|
||||||
|
|
||||||
compatibility_list.emplace(id.toUpper().toStdString(),
|
|
||||||
std::make_pair(QString::number(compatibility), directory));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListModel::Repopulate() {
|
void GameListModel::Repopulate() {
|
||||||
current_worker.reset();
|
current_worker.reset();
|
||||||
QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
|
QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
|
||||||
@@ -236,7 +192,6 @@ void GameListModel::ResetExternalWatcher() {
|
|||||||
|
|
||||||
void GameListModel::RetranslateUI() {
|
void GameListModel::RetranslateUI() {
|
||||||
setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
|
setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
|
||||||
setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, tr("Compatibility"));
|
|
||||||
setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
|
setHeaderData(COLUMN_ADD_ONS, Qt::Horizontal, tr("Add-ons"));
|
||||||
setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, tr("File type"));
|
||||||
setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
setHeaderData(COLUMN_SIZE, Qt::Horizontal, tr("Size"));
|
||||||
@@ -247,10 +202,6 @@ QFileSystemWatcher* GameListModel::GetWatcher() const {
|
|||||||
return watcher;
|
return watcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CompatibilityList& GameListModel::GetCompatibilityList() const {
|
|
||||||
return compatibility_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameListModel::SetFlat(bool flat) {
|
void GameListModel::SetFlat(bool flat) {
|
||||||
m_flat = flat;
|
m_flat = flat;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend_common/play_time_manager.h"
|
#include "frontend_common/play_time_manager.h"
|
||||||
#include "qt_common/config/uisettings.h"
|
#include "qt_common/config/uisettings.h"
|
||||||
#include "yuzu/compatibility_list.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
@@ -37,7 +36,6 @@ public:
|
|||||||
COLUMN_SIZE,
|
COLUMN_SIZE,
|
||||||
COLUMN_PLAY_TIME,
|
COLUMN_PLAY_TIME,
|
||||||
COLUMN_ADD_ONS,
|
COLUMN_ADD_ONS,
|
||||||
COLUMN_COMPATIBILITY,
|
|
||||||
COLUMN_COUNT,
|
COLUMN_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,14 +60,10 @@ public:
|
|||||||
void RefreshExternalContent();
|
void RefreshExternalContent();
|
||||||
void ResetExternalWatcher();
|
void ResetExternalWatcher();
|
||||||
|
|
||||||
void LoadCompatibilityList();
|
|
||||||
|
|
||||||
void RetranslateUI();
|
void RetranslateUI();
|
||||||
|
|
||||||
QFileSystemWatcher* GetWatcher() const;
|
QFileSystemWatcher* GetWatcher() const;
|
||||||
|
|
||||||
const CompatibilityList& GetCompatibilityList() const;
|
|
||||||
|
|
||||||
void SetFlat(bool flat);
|
void SetFlat(bool flat);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -89,7 +83,6 @@ private:
|
|||||||
|
|
||||||
std::shared_ptr<FileSys::VfsFilesystem> vfs;
|
std::shared_ptr<FileSys::VfsFilesystem> vfs;
|
||||||
FileSys::ManualContentProvider* provider;
|
FileSys::ManualContentProvider* provider;
|
||||||
CompatibilityList compatibility_list;
|
|
||||||
const PlayTime::PlayTimeManager& play_time_manager;
|
const PlayTime::PlayTimeManager& play_time_manager;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
#include "qt_common/qt_common.h"
|
#include "qt_common/qt_common.h"
|
||||||
|
|
||||||
#include "qt_common/game_list/game_list_p.h"
|
#include "qt_common/game_list/game_list_p.h"
|
||||||
#include "yuzu/compatibility_list.h"
|
|
||||||
|
|
||||||
#include "qt_common/game_list/model.h"
|
#include "qt_common/game_list/model.h"
|
||||||
#include "qt_common/game_list/worker.h"
|
#include "qt_common/game_list/worker.h"
|
||||||
@@ -203,14 +202,8 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
|
|||||||
QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
|
QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
|
||||||
const std::size_t size, const std::vector<u8>& icon,
|
const std::size_t size, const std::vector<u8>& icon,
|
||||||
Loader::AppLoader& loader, u64 program_id,
|
Loader::AppLoader& loader, u64 program_id,
|
||||||
const CompatibilityList& compatibility_list,
|
|
||||||
const PlayTime::PlayTimeManager& play_time_manager,
|
const PlayTime::PlayTimeManager& play_time_manager,
|
||||||
const FileSys::PatchManager& patch) {
|
const FileSys::PatchManager& patch) {
|
||||||
auto const it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
|
|
||||||
// The game list uses 99 as compatibility number for untested games
|
|
||||||
QString compatibility =
|
|
||||||
it != compatibility_list.end() ? it->second.first : QStringLiteral("99");
|
|
||||||
|
|
||||||
auto const file_type = loader.GetFileType();
|
auto const file_type = loader.GetFileType();
|
||||||
auto const file_type_string = QString::fromStdString(Loader::GetFileTypeString(file_type));
|
auto const file_type_string = QString::fromStdString(Loader::GetFileTypeString(file_type));
|
||||||
|
|
||||||
@@ -227,7 +220,6 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
|
|||||||
new GameListItemSize(size),
|
new GameListItemSize(size),
|
||||||
new GameListItemPlayTime(play_time),
|
new GameListItemPlayTime(play_time),
|
||||||
new GameListItem(patch_versions),
|
new GameListItem(patch_versions),
|
||||||
new GameListItemCompat(compatibility),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
@@ -235,11 +227,10 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::stri
|
|||||||
GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_,
|
GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_,
|
||||||
FileSys::ManualContentProvider* provider_,
|
FileSys::ManualContentProvider* provider_,
|
||||||
QVector<UISettings::GameDir>& game_dirs_,
|
QVector<UISettings::GameDir>& game_dirs_,
|
||||||
const CompatibilityList& compatibility_list_,
|
|
||||||
const PlayTime::PlayTimeManager& play_time_manager_,
|
const PlayTime::PlayTimeManager& play_time_manager_,
|
||||||
Core::System& system_)
|
Core::System& system_)
|
||||||
: vfs{std::move(vfs_)}, provider{provider_}, game_dirs{game_dirs_},
|
: vfs{std::move(vfs_)}, provider{provider_}, game_dirs{game_dirs_},
|
||||||
compatibility_list{compatibility_list_}, play_time_manager{play_time_manager_},
|
play_time_manager{play_time_manager_},
|
||||||
system{system_} {
|
system{system_} {
|
||||||
// We want the game list to manage our lifetime.
|
// We want the game list to manage our lifetime.
|
||||||
setAutoDelete(false);
|
setAutoDelete(false);
|
||||||
@@ -335,7 +326,7 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto entry = MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader,
|
auto entry = MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader,
|
||||||
program_id, compatibility_list, play_time_manager, patch);
|
program_id, play_time_manager, patch);
|
||||||
RecordEvent([=](GameListModel* model) { model->AddEntry(entry, parent_dir); });
|
RecordEvent([=](GameListModel* model) { model->AddEntry(entry, parent_dir); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -405,7 +396,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
|
|||||||
|
|
||||||
auto entry = MakeGameListEntry(
|
auto entry = MakeGameListEntry(
|
||||||
physical_name, name, Common::FS::GetSize(physical_name), icon, *app_loader,
|
physical_name, name, Common::FS::GetSize(physical_name), icon, *app_loader,
|
||||||
id, compatibility_list, play_time_manager, patch);
|
id, play_time_manager, patch);
|
||||||
|
|
||||||
RecordEvent([=](GameListModel* model) { model->AddEntry(entry, parent_dir); });
|
RecordEvent([=](GameListModel* model) { model->AddEntry(entry, parent_dir); });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include "core/file_sys/registered_cache.h"
|
#include "core/file_sys/registered_cache.h"
|
||||||
#include "frontend_common/play_time_manager.h"
|
#include "frontend_common/play_time_manager.h"
|
||||||
#include "qt_common/config/uisettings.h"
|
#include "qt_common/config/uisettings.h"
|
||||||
#include "yuzu/compatibility_list.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
class System;
|
class System;
|
||||||
@@ -46,7 +45,6 @@ public:
|
|||||||
explicit GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs_,
|
explicit GameListWorker(std::shared_ptr<FileSys::VfsFilesystem> vfs_,
|
||||||
FileSys::ManualContentProvider* provider_,
|
FileSys::ManualContentProvider* provider_,
|
||||||
QVector<UISettings::GameDir>& game_dirs_,
|
QVector<UISettings::GameDir>& game_dirs_,
|
||||||
const CompatibilityList& compatibility_list_,
|
|
||||||
const PlayTime::PlayTimeManager& play_time_manager_,
|
const PlayTime::PlayTimeManager& play_time_manager_,
|
||||||
Core::System& system_);
|
Core::System& system_);
|
||||||
~GameListWorker() override;
|
~GameListWorker() override;
|
||||||
@@ -85,7 +83,6 @@ private:
|
|||||||
std::shared_ptr<FileSys::VfsFilesystem> vfs;
|
std::shared_ptr<FileSys::VfsFilesystem> vfs;
|
||||||
FileSys::ManualContentProvider* provider;
|
FileSys::ManualContentProvider* provider;
|
||||||
QVector<UISettings::GameDir>& game_dirs;
|
QVector<UISettings::GameDir>& game_dirs;
|
||||||
const CompatibilityList& compatibility_list;
|
|
||||||
const PlayTime::PlayTimeManager& play_time_manager;
|
const PlayTime::PlayTimeManager& play_time_manager;
|
||||||
|
|
||||||
QStringList watch_list;
|
QStringList watch_list;
|
||||||
|
|||||||
@@ -465,12 +465,22 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
|||||||
ctx.AddCapability(spv::Capability::ImageGatherExtended);
|
ctx.AddCapability(spv::Capability::ImageGatherExtended);
|
||||||
ctx.AddCapability(spv::Capability::ImageQuery);
|
ctx.AddCapability(spv::Capability::ImageQuery);
|
||||||
ctx.AddCapability(spv::Capability::SampledBuffer);
|
ctx.AddCapability(spv::Capability::SampledBuffer);
|
||||||
// TODO: this usage needs to be tracked properly
|
if (!ctx.non_uniform_ids.empty()) {
|
||||||
if (ctx.profile.support_sampled_image_array_nonuniform_indexing) {
|
if (ctx.profile.supported_spirv < 0x00010500)
|
||||||
if (ctx.profile.supported_spirv < 0x00010400)
|
|
||||||
ctx.AddExtension("SPV_EXT_descriptor_indexing");
|
ctx.AddExtension("SPV_EXT_descriptor_indexing");
|
||||||
ctx.AddCapability(spv::Capability::ShaderNonUniform);
|
ctx.AddCapability(spv::Capability::ShaderNonUniform);
|
||||||
ctx.AddCapability(spv::Capability::SampledImageArrayNonUniformIndexing);
|
if (ctx.uses_nonuniform_sampled_image) {
|
||||||
|
ctx.AddCapability(spv::Capability::SampledImageArrayNonUniformIndexing);
|
||||||
|
}
|
||||||
|
if (ctx.uses_nonuniform_storage_image) {
|
||||||
|
ctx.AddCapability(spv::Capability::StorageImageArrayNonUniformIndexing);
|
||||||
|
}
|
||||||
|
if (ctx.uses_nonuniform_uniform_texel_buffer) {
|
||||||
|
ctx.AddCapability(spv::Capability::UniformTexelBufferArrayNonUniformIndexing);
|
||||||
|
}
|
||||||
|
if (ctx.uses_nonuniform_storage_texel_buffer) {
|
||||||
|
ctx.AddCapability(spv::Capability::StorageTexelBufferArrayNonUniformIndexing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -15,7 +18,7 @@ Id SharedPointer(EmitContext& ctx, Id offset, u32 index_offset = 0) {
|
|||||||
if (index_offset > 0) {
|
if (index_offset > 0) {
|
||||||
index = ctx.OpIAdd(ctx.U32[1], index, ctx.Const(index_offset));
|
index = ctx.OpIAdd(ctx.U32[1], index, ctx.Const(index_offset));
|
||||||
}
|
}
|
||||||
return ctx.profile.support_explicit_workgroup_layout
|
return ctx.uses_explicit_workgroup_layout
|
||||||
? ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, ctx.u32_zero_value, index)
|
? ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, ctx.u32_zero_value, index)
|
||||||
: ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index);
|
: ctx.OpAccessChain(ctx.shared_u32, ctx.shared_memory_u32, index);
|
||||||
}
|
}
|
||||||
@@ -155,7 +158,7 @@ Id EmitSharedAtomicExchange32(EmitContext& ctx, Id offset, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) {
|
Id EmitSharedAtomicExchange64(EmitContext& ctx, Id offset, Id value) {
|
||||||
if (ctx.profile.support_int64_atomics && ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.profile.support_shared_int64_atomics && ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id shift_id{ctx.Const(3U)};
|
const Id shift_id{ctx.Const(3U)};
|
||||||
const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
|
const Id index{ctx.OpShiftRightArithmetic(ctx.U32[1], offset, shift_id)};
|
||||||
const Id pointer{
|
const Id pointer{
|
||||||
|
|||||||
@@ -624,12 +624,14 @@ Id EmitRenderArea(EmitContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {
|
Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {
|
||||||
const Id pointer{ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset)};
|
const Id pointer{
|
||||||
|
ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset, ctx.Const(0U))};
|
||||||
return ctx.OpLoad(ctx.U32[1], pointer);
|
return ctx.OpLoad(ctx.U32[1], pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value) {
|
void EmitWriteLocal(EmitContext& ctx, Id word_offset, Id value) {
|
||||||
const Id pointer{ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset)};
|
const Id pointer{
|
||||||
|
ctx.OpAccessChain(ctx.private_u32, ctx.local_memory, word_offset, ctx.Const(0U))};
|
||||||
ctx.OpStore(pointer, value);
|
ctx.OpStore(pointer, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,56 @@
|
|||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[nodiscard]] bool IsNonUniformDescriptor(EmitContext& ctx, const IR::Value& index) noexcept {
|
enum class NonUniformKind {
|
||||||
return ctx.profile.support_sampled_image_array_nonuniform_indexing && !index.IsImmediate();
|
SampledImage,
|
||||||
|
StorageImage,
|
||||||
|
UniformTexelBuffer,
|
||||||
|
StorageTexelBuffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsNonUniformSupported(const Profile& profile, NonUniformKind kind) noexcept {
|
||||||
|
switch (kind) {
|
||||||
|
case NonUniformKind::SampledImage:
|
||||||
|
return profile.support_sampled_image_array_nonuniform_indexing;
|
||||||
|
case NonUniformKind::StorageImage:
|
||||||
|
return profile.support_storage_image_array_nonuniform_indexing;
|
||||||
|
case NonUniformKind::UniformTexelBuffer:
|
||||||
|
return profile.support_uniform_texel_buffer_array_nonuniform_indexing;
|
||||||
|
case NonUniformKind::StorageTexelBuffer:
|
||||||
|
return profile.support_storage_texel_buffer_array_nonuniform_indexing;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecorateNonUniform(EmitContext& ctx, Id object) {
|
||||||
|
if (ctx.non_uniform_ids.contains(object.value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.Decorate(object, spv::Decoration::NonUniform);
|
||||||
|
ctx.non_uniform_ids.insert(object.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool MarkNonUniform(EmitContext& ctx, Id idx, const IR::Value& index,
|
||||||
|
NonUniformKind kind) {
|
||||||
|
if (index.IsImmediate() || !IsNonUniformSupported(ctx.profile, kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DecorateNonUniform(ctx, idx);
|
||||||
|
switch (kind) {
|
||||||
|
case NonUniformKind::SampledImage:
|
||||||
|
ctx.uses_nonuniform_sampled_image = true;
|
||||||
|
break;
|
||||||
|
case NonUniformKind::StorageImage:
|
||||||
|
ctx.uses_nonuniform_storage_image = true;
|
||||||
|
break;
|
||||||
|
case NonUniformKind::UniformTexelBuffer:
|
||||||
|
ctx.uses_nonuniform_uniform_texel_buffer = true;
|
||||||
|
break;
|
||||||
|
case NonUniformKind::StorageTexelBuffer:
|
||||||
|
ctx.uses_nonuniform_storage_texel_buffer = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageOperands {
|
class ImageOperands {
|
||||||
@@ -195,12 +243,13 @@ Id Texture(EmitContext& ctx, IR::TextureInstInfo info, [[maybe_unused]] const IR
|
|||||||
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
auto const idx = index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index);
|
auto const idx = index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index);
|
||||||
if (!ctx.non_uniform_ids.contains(idx.value) && IsNonUniformDescriptor(ctx, index)) {
|
const bool non_uniform{MarkNonUniform(ctx, idx, index, NonUniformKind::SampledImage)};
|
||||||
ctx.Decorate(idx, spv::Decoration::NonUniform);
|
|
||||||
ctx.non_uniform_ids.insert(idx.value);
|
|
||||||
}
|
|
||||||
const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
const Id pointer{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
||||||
const Id object{ctx.OpLoad(def.sampled_type, pointer)};
|
const Id object{ctx.OpLoad(def.sampled_type, pointer)};
|
||||||
|
if (non_uniform) {
|
||||||
|
DecorateNonUniform(ctx, pointer);
|
||||||
|
DecorateNonUniform(ctx, object);
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
} else {
|
} else {
|
||||||
return ctx.OpLoad(def.sampled_type, def.id);
|
return ctx.OpLoad(def.sampled_type, def.id);
|
||||||
@@ -212,21 +261,30 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind
|
|||||||
const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)};
|
const TextureBufferDefinition& def{ctx.texture_buffers.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
||||||
|
const bool non_uniform{
|
||||||
|
MarkNonUniform(ctx, idx, index, NonUniformKind::UniformTexelBuffer)};
|
||||||
const Id ptr{ctx.OpAccessChain(ctx.image_buffer_type, def.id, idx)};
|
const Id ptr{ctx.OpAccessChain(ctx.image_buffer_type, def.id, idx)};
|
||||||
return ctx.OpLoad(ctx.image_buffer_type, ptr);
|
const Id object{ctx.OpLoad(ctx.image_buffer_type, ptr)};
|
||||||
|
if (non_uniform) {
|
||||||
|
DecorateNonUniform(ctx, ptr);
|
||||||
|
DecorateNonUniform(ctx, object);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
}
|
}
|
||||||
return ctx.OpLoad(ctx.image_buffer_type, def.id);
|
return ctx.OpLoad(ctx.image_buffer_type, def.id);
|
||||||
} else {
|
} else {
|
||||||
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
const TextureDefinition& def{ctx.textures.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
auto const idx = index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index);
|
auto const idx = index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index);
|
||||||
if (!ctx.non_uniform_ids.contains(idx.value) && IsNonUniformDescriptor(ctx, index)) {
|
const bool non_uniform{MarkNonUniform(ctx, idx, index, NonUniformKind::SampledImage)};
|
||||||
ctx.Decorate(idx, spv::Decoration::NonUniform);
|
|
||||||
ctx.non_uniform_ids.insert(idx.value);
|
|
||||||
}
|
|
||||||
const Id ptr = ctx.OpAccessChain(def.pointer_type, def.id, idx);
|
const Id ptr = ctx.OpAccessChain(def.pointer_type, def.id, idx);
|
||||||
const Id object = ctx.OpLoad(def.sampled_type, ptr);
|
const Id object = ctx.OpLoad(def.sampled_type, ptr);
|
||||||
const Id image = ctx.OpImage(def.image_type, object);
|
const Id image = ctx.OpImage(def.image_type, object);
|
||||||
|
if (non_uniform) {
|
||||||
|
DecorateNonUniform(ctx, ptr);
|
||||||
|
DecorateNonUniform(ctx, object);
|
||||||
|
DecorateNonUniform(ctx, image);
|
||||||
|
}
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
|
return ctx.OpImage(def.image_type, ctx.OpLoad(def.sampled_type, def.id));
|
||||||
@@ -238,16 +296,29 @@ std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureI
|
|||||||
const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)};
|
const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
||||||
|
const bool non_uniform{
|
||||||
|
MarkNonUniform(ctx, idx, index, NonUniformKind::StorageTexelBuffer)};
|
||||||
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
||||||
return {ctx.OpLoad(def.image_type, ptr), def.is_integer};
|
const Id image{ctx.OpLoad(def.image_type, ptr)};
|
||||||
|
if (non_uniform) {
|
||||||
|
DecorateNonUniform(ctx, ptr);
|
||||||
|
DecorateNonUniform(ctx, image);
|
||||||
|
}
|
||||||
|
return {image, def.is_integer};
|
||||||
}
|
}
|
||||||
return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
|
return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
|
||||||
} else {
|
} else {
|
||||||
const ImageDefinition def{ctx.images.at(info.descriptor_index)};
|
const ImageDefinition def{ctx.images.at(info.descriptor_index)};
|
||||||
if (def.count > 1) {
|
if (def.count > 1) {
|
||||||
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
const Id idx{index.IsImmediate() ? ctx.Const(index.U32()) : ctx.Def(index)};
|
||||||
|
const bool non_uniform{MarkNonUniform(ctx, idx, index, NonUniformKind::StorageImage)};
|
||||||
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
const Id ptr{ctx.OpAccessChain(def.pointer_type, def.id, idx)};
|
||||||
return {ctx.OpLoad(def.image_type, ptr), def.is_integer};
|
const Id image{ctx.OpLoad(def.image_type, ptr)};
|
||||||
|
if (non_uniform) {
|
||||||
|
DecorateNonUniform(ctx, ptr);
|
||||||
|
DecorateNonUniform(ctx, image);
|
||||||
|
}
|
||||||
|
return {image, def.is_integer};
|
||||||
}
|
}
|
||||||
return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
|
return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ void EmitWriteGlobal128(EmitContext& ctx, Id address, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitLoadStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (ctx.profile.support_int8 && ctx.profile.support_uniform_and_storage_buffer_8bit &&
|
if (ctx.profile.support_int8 && ctx.profile.support_storage_buffer_8bit &&
|
||||||
ctx.profile.support_descriptor_aliasing) {
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
return ctx.OpUConvert(ctx.U32[1],
|
return ctx.OpUConvert(ctx.U32[1],
|
||||||
LoadStorage(ctx, binding, offset, ctx.U8, ctx.storage_types.U8,
|
LoadStorage(ctx, binding, offset, ctx.U8, ctx.storage_types.U8,
|
||||||
@@ -171,7 +171,7 @@ Id EmitLoadStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitLoadStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (ctx.profile.support_int8 && ctx.profile.support_uniform_and_storage_buffer_8bit &&
|
if (ctx.profile.support_int8 && ctx.profile.support_storage_buffer_8bit &&
|
||||||
ctx.profile.support_descriptor_aliasing) {
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
return ctx.OpSConvert(ctx.U32[1],
|
return ctx.OpSConvert(ctx.U32[1],
|
||||||
LoadStorage(ctx, binding, offset, ctx.S8, ctx.storage_types.S8,
|
LoadStorage(ctx, binding, offset, ctx.S8, ctx.storage_types.S8,
|
||||||
@@ -183,7 +183,7 @@ Id EmitLoadStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitLoadStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (ctx.profile.support_int16 && ctx.profile.support_uniform_and_storage_buffer_16bit &&
|
if (ctx.profile.support_int16 && ctx.profile.support_storage_buffer_16bit &&
|
||||||
ctx.profile.support_descriptor_aliasing) {
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
return ctx.OpUConvert(ctx.U32[1],
|
return ctx.OpUConvert(ctx.U32[1],
|
||||||
LoadStorage(ctx, binding, offset, ctx.U16, ctx.storage_types.U16,
|
LoadStorage(ctx, binding, offset, ctx.U16, ctx.storage_types.U16,
|
||||||
@@ -195,7 +195,7 @@ Id EmitLoadStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitLoadStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (ctx.profile.support_int16 && ctx.profile.support_uniform_and_storage_buffer_16bit &&
|
if (ctx.profile.support_int16 && ctx.profile.support_storage_buffer_16bit &&
|
||||||
ctx.profile.support_descriptor_aliasing) {
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
return ctx.OpSConvert(ctx.U32[1],
|
return ctx.OpSConvert(ctx.U32[1],
|
||||||
LoadStorage(ctx, binding, offset, ctx.S16, ctx.storage_types.S16,
|
LoadStorage(ctx, binding, offset, ctx.S16, ctx.storage_types.S16,
|
||||||
@@ -234,7 +234,8 @@ Id EmitLoadStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Valu
|
|||||||
|
|
||||||
void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int8 && ctx.profile.support_uniform_and_storage_buffer_8bit) {
|
if (ctx.profile.support_int8 && ctx.profile.support_storage_buffer_8bit &&
|
||||||
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8,
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8,
|
||||||
sizeof(u8), &StorageDefinitions::U8);
|
sizeof(u8), &StorageDefinitions::U8);
|
||||||
} else {
|
} else {
|
||||||
@@ -244,7 +245,8 @@ void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Va
|
|||||||
|
|
||||||
void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int8 && ctx.profile.support_uniform_and_storage_buffer_8bit) {
|
if (ctx.profile.support_int8 && ctx.profile.support_storage_buffer_8bit &&
|
||||||
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8,
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8,
|
||||||
sizeof(s8), &StorageDefinitions::S8);
|
sizeof(s8), &StorageDefinitions::S8);
|
||||||
} else {
|
} else {
|
||||||
@@ -254,7 +256,8 @@ void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Va
|
|||||||
|
|
||||||
void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int16 && ctx.profile.support_uniform_and_storage_buffer_16bit) {
|
if (ctx.profile.support_int16 && ctx.profile.support_storage_buffer_16bit &&
|
||||||
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16,
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16,
|
||||||
sizeof(u16), &StorageDefinitions::U16);
|
sizeof(u16), &StorageDefinitions::U16);
|
||||||
} else {
|
} else {
|
||||||
@@ -264,7 +267,8 @@ void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::V
|
|||||||
|
|
||||||
void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int16 && ctx.profile.support_uniform_and_storage_buffer_16bit) {
|
if (ctx.profile.support_int16 && ctx.profile.support_storage_buffer_16bit &&
|
||||||
|
ctx.profile.support_descriptor_aliasing) {
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16,
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16,
|
||||||
sizeof(s16), &StorageDefinitions::S16);
|
sizeof(s16), &StorageDefinitions::S16);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ std::pair<Id, Id> ExtractArgs(EmitContext& ctx, Id offset, u32 mask, u32 count)
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
Id EmitLoadSharedU8(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedU8(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{
|
const Id pointer{
|
||||||
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
||||||
return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U8, pointer));
|
return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U8, pointer));
|
||||||
@@ -42,7 +42,7 @@ Id EmitLoadSharedU8(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadSharedS8(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedS8(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{
|
const Id pointer{
|
||||||
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
||||||
return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U8, pointer));
|
return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U8, pointer));
|
||||||
@@ -53,7 +53,7 @@ Id EmitLoadSharedS8(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadSharedU16(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedU16(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
||||||
return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
|
return ctx.OpUConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
|
||||||
} else {
|
} else {
|
||||||
@@ -63,7 +63,7 @@ Id EmitLoadSharedU16(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadSharedS16(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedS16(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
||||||
return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
|
return ctx.OpSConvert(ctx.U32[1], ctx.OpLoad(ctx.U16, pointer));
|
||||||
} else {
|
} else {
|
||||||
@@ -73,7 +73,7 @@ Id EmitLoadSharedS16(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadSharedU32(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedU32(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2)};
|
const Id pointer{Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2)};
|
||||||
return ctx.OpLoad(ctx.U32[1], pointer);
|
return ctx.OpLoad(ctx.U32[1], pointer);
|
||||||
} else {
|
} else {
|
||||||
@@ -82,7 +82,7 @@ Id EmitLoadSharedU32(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
|
const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
|
||||||
return ctx.OpLoad(ctx.U32[2], pointer);
|
return ctx.OpLoad(ctx.U32[2], pointer);
|
||||||
} else {
|
} else {
|
||||||
@@ -97,7 +97,7 @@ Id EmitLoadSharedU64(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
|
Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
|
const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
|
||||||
return ctx.OpLoad(ctx.U32[4], pointer);
|
return ctx.OpLoad(ctx.U32[4], pointer);
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ Id EmitLoadSharedU128(EmitContext& ctx, Id offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteSharedU8(EmitContext& ctx, Id offset, Id value) {
|
void EmitWriteSharedU8(EmitContext& ctx, Id offset, Id value) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{
|
const Id pointer{
|
||||||
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
ctx.OpAccessChain(ctx.shared_u8, ctx.shared_memory_u8, ctx.u32_zero_value, offset)};
|
||||||
ctx.OpStore(pointer, ctx.OpUConvert(ctx.U8, value));
|
ctx.OpStore(pointer, ctx.OpUConvert(ctx.U8, value));
|
||||||
@@ -123,7 +123,7 @@ void EmitWriteSharedU8(EmitContext& ctx, Id offset, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteSharedU16(EmitContext& ctx, Id offset, Id value) {
|
void EmitWriteSharedU16(EmitContext& ctx, Id offset, Id value) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
const Id pointer{Pointer(ctx, ctx.shared_u16, ctx.shared_memory_u16, offset, 1)};
|
||||||
ctx.OpStore(pointer, ctx.OpUConvert(ctx.U16, value));
|
ctx.OpStore(pointer, ctx.OpUConvert(ctx.U16, value));
|
||||||
} else {
|
} else {
|
||||||
@@ -133,7 +133,7 @@ void EmitWriteSharedU16(EmitContext& ctx, Id offset, Id value) {
|
|||||||
|
|
||||||
void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
||||||
Id pointer{};
|
Id pointer{};
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
pointer = Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2);
|
pointer = Pointer(ctx, ctx.shared_u32, ctx.shared_memory_u32, offset, 2);
|
||||||
} else {
|
} else {
|
||||||
const Id shift{ctx.Const(2U)};
|
const Id shift{ctx.Const(2U)};
|
||||||
@@ -144,7 +144,7 @@ void EmitWriteSharedU32(EmitContext& ctx, Id offset, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
|
void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
|
const Id pointer{Pointer(ctx, ctx.shared_u32x2, ctx.shared_memory_u32x2, offset, 3)};
|
||||||
ctx.OpStore(pointer, value);
|
ctx.OpStore(pointer, value);
|
||||||
return;
|
return;
|
||||||
@@ -159,7 +159,7 @@ void EmitWriteSharedU64(EmitContext& ctx, Id offset, Id value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value) {
|
void EmitWriteSharedU128(EmitContext& ctx, Id offset, Id value) {
|
||||||
if (ctx.profile.support_explicit_workgroup_layout) {
|
if (ctx.uses_explicit_workgroup_layout) {
|
||||||
const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
|
const Id pointer{Pointer(ctx, ctx.shared_u32x4, ctx.shared_memory_u32x4, offset, 4)};
|
||||||
ctx.OpStore(pointer, value);
|
ctx.OpStore(pointer, value);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ Id CasFunction(EmitContext& ctx, Operation operation, Id value_type) {
|
|||||||
Id CasLoop(EmitContext& ctx, Operation operation, Id array_pointer, Id element_pointer,
|
Id CasLoop(EmitContext& ctx, Operation operation, Id array_pointer, Id element_pointer,
|
||||||
Id value_type, Id memory_type, spv::Scope scope) {
|
Id value_type, Id memory_type, spv::Scope scope) {
|
||||||
const bool is_shared{scope == spv::Scope::Workgroup};
|
const bool is_shared{scope == spv::Scope::Workgroup};
|
||||||
const bool is_struct{!is_shared || ctx.profile.support_explicit_workgroup_layout};
|
const bool is_struct{!is_shared || ctx.uses_explicit_workgroup_layout};
|
||||||
const Id cas_func{CasFunction(ctx, operation, value_type)};
|
const Id cas_func{CasFunction(ctx, operation, value_type)};
|
||||||
const Id zero{ctx.u32_zero_value};
|
const Id zero{ctx.u32_zero_value};
|
||||||
const Id scope_id{ctx.Const(static_cast<u32>(scope))};
|
const Id scope_id{ctx.Const(static_cast<u32>(scope))};
|
||||||
@@ -591,7 +591,8 @@ void EmitContext::DefineLocalMemory(const IR::Program& program) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const u32 num_elements{Common::DivCeil(program.local_memory_size, 4U)};
|
const u32 num_elements{Common::DivCeil(program.local_memory_size, 4U)};
|
||||||
const Id type{TypeArray(U32[1], Const(num_elements))};
|
const Id element_type{TypeStruct(U32[1])};
|
||||||
|
const Id type{TypeArray(element_type, Const(num_elements))};
|
||||||
const Id pointer{TypePointer(spv::StorageClass::Private, type)};
|
const Id pointer{TypePointer(spv::StorageClass::Private, type)};
|
||||||
local_memory = AddGlobalVariable(pointer, spv::StorageClass::Private);
|
local_memory = AddGlobalVariable(pointer, spv::StorageClass::Private);
|
||||||
if (profile.supported_spirv >= 0x00010400) {
|
if (profile.supported_spirv >= 0x00010400) {
|
||||||
@@ -600,6 +601,10 @@ void EmitContext::DefineLocalMemory(const IR::Program& program) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitContext::DefineSharedMemory(const IR::Program& program) {
|
void EmitContext::DefineSharedMemory(const IR::Program& program) {
|
||||||
|
uses_explicit_workgroup_layout =
|
||||||
|
profile.support_explicit_workgroup_layout &&
|
||||||
|
(!program.info.uses_int8 || profile.support_workgroup_layout_8bit_access) &&
|
||||||
|
(!program.info.uses_int16 || profile.support_workgroup_layout_16bit_access);
|
||||||
if (program.shared_memory_size == 0) {
|
if (program.shared_memory_size == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -620,18 +625,18 @@ void EmitContext::DefineSharedMemory(const IR::Program& program) {
|
|||||||
|
|
||||||
return std::make_tuple(variable, element_pointer, pointer);
|
return std::make_tuple(variable, element_pointer, pointer);
|
||||||
}};
|
}};
|
||||||
if (profile.support_explicit_workgroup_layout) {
|
if (uses_explicit_workgroup_layout) {
|
||||||
AddExtension("SPV_KHR_workgroup_memory_explicit_layout");
|
AddExtension("SPV_KHR_workgroup_memory_explicit_layout");
|
||||||
AddCapability(spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
|
AddCapability(spv::Capability::WorkgroupMemoryExplicitLayoutKHR);
|
||||||
if (program.info.uses_int8) {
|
if (program.info.uses_int8 && profile.support_int8) {
|
||||||
AddCapability(spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR);
|
AddCapability(spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR);
|
||||||
std::tie(shared_memory_u8, shared_u8, std::ignore) = make(U8, 1);
|
std::tie(shared_memory_u8, shared_u8, std::ignore) = make(U8, 1);
|
||||||
}
|
}
|
||||||
if (program.info.uses_int16) {
|
if (program.info.uses_int16 && profile.support_int16) {
|
||||||
AddCapability(spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR);
|
AddCapability(spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR);
|
||||||
std::tie(shared_memory_u16, shared_u16, std::ignore) = make(U16, 2);
|
std::tie(shared_memory_u16, shared_u16, std::ignore) = make(U16, 2);
|
||||||
}
|
}
|
||||||
if (program.info.uses_int64) {
|
if (program.info.uses_int64 && profile.support_int64) {
|
||||||
std::tie(shared_memory_u64, shared_u64, std::ignore) = make(U64, 8);
|
std::tie(shared_memory_u64, shared_u64, std::ignore) = make(U64, 8);
|
||||||
}
|
}
|
||||||
std::tie(shared_memory_u32, shared_u32, shared_memory_u32_type) = make(U32[1], 4);
|
std::tie(shared_memory_u32, shared_u32, shared_memory_u32_type) = make(U32[1], 4);
|
||||||
@@ -1229,16 +1234,17 @@ void EmitContext::DefineStorageBuffers(const Info& info, u32& binding) {
|
|||||||
}
|
}
|
||||||
AddExtension("SPV_KHR_storage_buffer_storage_class");
|
AddExtension("SPV_KHR_storage_buffer_storage_class");
|
||||||
|
|
||||||
const IR::Type used_types{profile.support_descriptor_aliasing ? info.used_storage_buffer_types
|
IR::Type used_types{profile.support_descriptor_aliasing ? info.used_storage_buffer_types
|
||||||
: IR::Type::U32};
|
: IR::Type::U32};
|
||||||
if (profile.support_int8 && profile.support_uniform_and_storage_buffer_8bit &&
|
used_types |= IR::Type::U32;
|
||||||
|
if (profile.support_int8 && profile.support_storage_buffer_8bit &&
|
||||||
True(used_types & IR::Type::U8)) {
|
True(used_types & IR::Type::U8)) {
|
||||||
DefineSsbos(*this, storage_types.U8, &StorageDefinitions::U8, info, binding, U8,
|
DefineSsbos(*this, storage_types.U8, &StorageDefinitions::U8, info, binding, U8,
|
||||||
sizeof(u8));
|
sizeof(u8));
|
||||||
DefineSsbos(*this, storage_types.S8, &StorageDefinitions::S8, info, binding, S8,
|
DefineSsbos(*this, storage_types.S8, &StorageDefinitions::S8, info, binding, S8,
|
||||||
sizeof(u8));
|
sizeof(u8));
|
||||||
}
|
}
|
||||||
if (profile.support_int16 && profile.support_uniform_and_storage_buffer_16bit &&
|
if (profile.support_int16 && profile.support_storage_buffer_16bit &&
|
||||||
True(used_types & IR::Type::U16)) {
|
True(used_types & IR::Type::U16)) {
|
||||||
DefineSsbos(*this, storage_types.U16, &StorageDefinitions::U16, info, binding, U16,
|
DefineSsbos(*this, storage_types.U16, &StorageDefinitions::U16, info, binding, U16,
|
||||||
sizeof(u16));
|
sizeof(u16));
|
||||||
|
|||||||
@@ -311,6 +311,7 @@ public:
|
|||||||
|
|
||||||
Id local_memory{};
|
Id local_memory{};
|
||||||
|
|
||||||
|
bool uses_explicit_workgroup_layout{};
|
||||||
Id shared_memory_u8{};
|
Id shared_memory_u8{};
|
||||||
Id shared_memory_u16{};
|
Id shared_memory_u16{};
|
||||||
Id shared_memory_u32{};
|
Id shared_memory_u32{};
|
||||||
@@ -371,6 +372,11 @@ public:
|
|||||||
// Sirit::Id doesn't play nice with *::set<>
|
// Sirit::Id doesn't play nice with *::set<>
|
||||||
ankerl::unordered_dense::set<u32> non_uniform_ids;
|
ankerl::unordered_dense::set<u32> non_uniform_ids;
|
||||||
|
|
||||||
|
bool uses_nonuniform_sampled_image{};
|
||||||
|
bool uses_nonuniform_storage_image{};
|
||||||
|
bool uses_nonuniform_uniform_texel_buffer{};
|
||||||
|
bool uses_nonuniform_storage_texel_buffer{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DefineCommonTypes(const Info& info);
|
void DefineCommonTypes(const Info& info);
|
||||||
void DefineCommonConstants();
|
void DefineCommonConstants();
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -181,6 +184,72 @@ void ShiftRightArithmetic64To32(IR::Block& block, IR::Inst& inst) {
|
|||||||
inst.ReplaceUsesWith(ir.CompositeConstruct(ret_lo, ret_hi));
|
inst.ReplaceUsesWith(ir.CompositeConstruct(ret_lo, ret_hi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IAbs64To32(IR::Block& block, IR::Inst& inst) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
const auto [lo, hi]{Unpack(ir, inst.Arg(0))};
|
||||||
|
|
||||||
|
const IR::U32 neg_lo{ir.IAdd(ir.BitwiseNot(lo), ir.Imm32(1))};
|
||||||
|
const IR::U32 carry{IR::U32{ir.Select(ir.GetCarryFromOp(neg_lo), ir.Imm32(1u), ir.Imm32(0u))}};
|
||||||
|
const IR::U32 neg_hi{ir.IAdd(ir.BitwiseNot(hi), carry)};
|
||||||
|
|
||||||
|
const IR::U1 is_negative{ir.INotEqual(ir.BitwiseAnd(hi, ir.Imm32(0x80000000u)), ir.Imm32(0u))};
|
||||||
|
const IR::U32 ret_lo{IR::U32{ir.Select(is_negative, neg_lo, lo)}};
|
||||||
|
const IR::U32 ret_hi{IR::U32{ir.Select(is_negative, neg_hi, hi)}};
|
||||||
|
inst.ReplaceUsesWith(ir.CompositeConstruct(ret_lo, ret_hi));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectU64To32(IR::Block& block, IR::Inst& inst) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
const IR::U1 condition{inst.Arg(0)};
|
||||||
|
const auto [true_lo, true_hi]{Unpack(ir, inst.Arg(1))};
|
||||||
|
const auto [false_lo, false_hi]{Unpack(ir, inst.Arg(2))};
|
||||||
|
|
||||||
|
const IR::U32 ret_lo{IR::U32{ir.Select(condition, true_lo, false_lo)}};
|
||||||
|
const IR::U32 ret_hi{IR::U32{ir.Select(condition, true_hi, false_hi)}};
|
||||||
|
inst.ReplaceUsesWith(ir.CompositeConstruct(ret_lo, ret_hi));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UndefU64To32(IR::Block& block, IR::Inst& inst) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
inst.ReplaceUsesWith(ir.CompositeConstruct(ir.Imm32(0u), ir.Imm32(0u)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertU64U32To32(IR::Block& block, IR::Inst& inst) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
inst.ReplaceUsesWith(ir.CompositeConstruct(IR::U32{inst.Arg(0)}, ir.Imm32(0u)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertU32U64To32(IR::Block& block, IR::Inst& inst) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
inst.ReplaceUsesWith(Unpack(ir, inst.Arg(0)).first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntToFloat64To32(IR::Block& block, IR::Inst& inst, bool is_signed, size_t dest_bitsize) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
const auto [lo, hi]{Unpack(ir, inst.Arg(0))};
|
||||||
|
const IR::F32 low{ir.ConvertUToF(32, 32, lo)};
|
||||||
|
const IR::F32 high{is_signed ? IR::F32{ir.ConvertSToF(32, 32, hi)}
|
||||||
|
: IR::F32{ir.ConvertUToF(32, 32, hi)}};
|
||||||
|
const IR::F32 combined{ir.FPFma(high, ir.Imm32(4294967296.0f), low)};
|
||||||
|
if (dest_bitsize == 32) {
|
||||||
|
inst.ReplaceUsesWith(combined);
|
||||||
|
} else {
|
||||||
|
inst.ReplaceUsesWith(ir.FPConvert(dest_bitsize, combined));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FloatToInt64To32(IR::Block& block, IR::Inst& inst, bool is_signed, size_t src_bitsize) {
|
||||||
|
IR::IREmitter ir(block, IR::Block::InstructionList::s_iterator_to(inst));
|
||||||
|
const IR::F32 value{src_bitsize == 32 ? IR::F32{inst.Arg(0)}
|
||||||
|
: IR::F32{ir.FPConvert(32, IR::F16F32F64{inst.Arg(0)})}};
|
||||||
|
const IR::F32 high_f{ir.FPFloor(ir.FPMul(value, ir.Imm32(1.0f / 4294967296.0f)))};
|
||||||
|
const IR::U32 hi{is_signed ? IR::U32{ir.ConvertFToS(32, high_f)}
|
||||||
|
: IR::U32{ir.ConvertFToU(32, high_f)}};
|
||||||
|
const IR::F32 low_f{ir.FPFma(high_f, ir.FPNeg(ir.Imm32(4294967296.0f)), value)};
|
||||||
|
const IR::U32 lo{IR::U32{ir.ConvertFToU(32, low_f)}};
|
||||||
|
inst.ReplaceUsesWith(ir.CompositeConstruct(lo, hi));
|
||||||
|
}
|
||||||
|
|
||||||
void Lower(IR::Block& block, IR::Inst& inst) {
|
void Lower(IR::Block& block, IR::Inst& inst) {
|
||||||
switch (inst.GetOpcode()) {
|
switch (inst.GetOpcode()) {
|
||||||
case IR::Opcode::PackUint2x32:
|
case IR::Opcode::PackUint2x32:
|
||||||
@@ -218,6 +287,62 @@ void Lower(IR::Block& block, IR::Inst& inst) {
|
|||||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicXor32x2);
|
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicXor32x2);
|
||||||
case IR::Opcode::GlobalAtomicExchange64:
|
case IR::Opcode::GlobalAtomicExchange64:
|
||||||
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicExchange32x2);
|
return inst.ReplaceOpcode(IR::Opcode::GlobalAtomicExchange32x2);
|
||||||
|
case IR::Opcode::StorageAtomicIAdd64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicIAdd32x2);
|
||||||
|
case IR::Opcode::StorageAtomicSMin64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicSMin32x2);
|
||||||
|
case IR::Opcode::StorageAtomicUMin64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicUMin32x2);
|
||||||
|
case IR::Opcode::StorageAtomicSMax64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicSMax32x2);
|
||||||
|
case IR::Opcode::StorageAtomicUMax64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicUMax32x2);
|
||||||
|
case IR::Opcode::StorageAtomicAnd64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicAnd32x2);
|
||||||
|
case IR::Opcode::StorageAtomicOr64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicOr32x2);
|
||||||
|
case IR::Opcode::StorageAtomicXor64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicXor32x2);
|
||||||
|
case IR::Opcode::StorageAtomicExchange64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::StorageAtomicExchange32x2);
|
||||||
|
case IR::Opcode::BitCastU64F64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::UnpackDouble2x32);
|
||||||
|
case IR::Opcode::BitCastF64U64:
|
||||||
|
return inst.ReplaceOpcode(IR::Opcode::PackDouble2x32);
|
||||||
|
case IR::Opcode::UndefU64:
|
||||||
|
return UndefU64To32(block, inst);
|
||||||
|
case IR::Opcode::SelectU64:
|
||||||
|
return SelectU64To32(block, inst);
|
||||||
|
case IR::Opcode::IAbs64:
|
||||||
|
return IAbs64To32(block, inst);
|
||||||
|
case IR::Opcode::ConvertU64U32:
|
||||||
|
return ConvertU64U32To32(block, inst);
|
||||||
|
case IR::Opcode::ConvertU32U64:
|
||||||
|
return ConvertU32U64To32(block, inst);
|
||||||
|
case IR::Opcode::ConvertS64F16:
|
||||||
|
return FloatToInt64To32(block, inst, true, 16);
|
||||||
|
case IR::Opcode::ConvertS64F32:
|
||||||
|
return FloatToInt64To32(block, inst, true, 32);
|
||||||
|
case IR::Opcode::ConvertS64F64:
|
||||||
|
return FloatToInt64To32(block, inst, true, 64);
|
||||||
|
case IR::Opcode::ConvertU64F16:
|
||||||
|
return FloatToInt64To32(block, inst, false, 16);
|
||||||
|
case IR::Opcode::ConvertU64F32:
|
||||||
|
return FloatToInt64To32(block, inst, false, 32);
|
||||||
|
case IR::Opcode::ConvertU64F64:
|
||||||
|
return FloatToInt64To32(block, inst, false, 64);
|
||||||
|
case IR::Opcode::ConvertF16S64:
|
||||||
|
return IntToFloat64To32(block, inst, true, 16);
|
||||||
|
case IR::Opcode::ConvertF32S64:
|
||||||
|
return IntToFloat64To32(block, inst, true, 32);
|
||||||
|
case IR::Opcode::ConvertF64S64:
|
||||||
|
return IntToFloat64To32(block, inst, true, 64);
|
||||||
|
case IR::Opcode::ConvertF16U64:
|
||||||
|
return IntToFloat64To32(block, inst, false, 16);
|
||||||
|
case IR::Opcode::ConvertF32U64:
|
||||||
|
return IntToFloat64To32(block, inst, false, 32);
|
||||||
|
case IR::Opcode::ConvertF64U64:
|
||||||
|
return IntToFloat64To32(block, inst, false, 64);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ struct Profile {
|
|||||||
bool support_descriptor_aliasing{};
|
bool support_descriptor_aliasing{};
|
||||||
bool support_int8{};
|
bool support_int8{};
|
||||||
bool support_uniform_and_storage_buffer_8bit{};
|
bool support_uniform_and_storage_buffer_8bit{};
|
||||||
|
bool support_storage_buffer_8bit{};
|
||||||
bool support_int16{};
|
bool support_int16{};
|
||||||
bool support_uniform_and_storage_buffer_16bit{};
|
bool support_uniform_and_storage_buffer_16bit{};
|
||||||
|
bool support_storage_buffer_16bit{};
|
||||||
bool support_int64{};
|
bool support_int64{};
|
||||||
bool support_vertex_instance_id{};
|
bool support_vertex_instance_id{};
|
||||||
bool support_float_controls{};
|
bool support_float_controls{};
|
||||||
@@ -33,6 +35,8 @@ struct Profile {
|
|||||||
bool support_fp32_signed_zero_nan_preserve{};
|
bool support_fp32_signed_zero_nan_preserve{};
|
||||||
bool support_fp64_signed_zero_nan_preserve{};
|
bool support_fp64_signed_zero_nan_preserve{};
|
||||||
bool support_explicit_workgroup_layout{};
|
bool support_explicit_workgroup_layout{};
|
||||||
|
bool support_workgroup_layout_8bit_access{};
|
||||||
|
bool support_workgroup_layout_16bit_access{};
|
||||||
bool support_vote{};
|
bool support_vote{};
|
||||||
u32 supported_subgroup_stages{0x7F};
|
u32 supported_subgroup_stages{0x7F};
|
||||||
bool support_viewport_index_layer_non_geometry{};
|
bool support_viewport_index_layer_non_geometry{};
|
||||||
@@ -40,6 +44,7 @@ struct Profile {
|
|||||||
bool support_typeless_image_loads{};
|
bool support_typeless_image_loads{};
|
||||||
bool support_demote_to_helper_invocation{};
|
bool support_demote_to_helper_invocation{};
|
||||||
bool support_int64_atomics{};
|
bool support_int64_atomics{};
|
||||||
|
bool support_shared_int64_atomics{};
|
||||||
bool support_derivative_control{};
|
bool support_derivative_control{};
|
||||||
bool support_geometry_shader_passthrough{};
|
bool support_geometry_shader_passthrough{};
|
||||||
bool support_native_ndc{};
|
bool support_native_ndc{};
|
||||||
@@ -54,6 +59,9 @@ struct Profile {
|
|||||||
bool support_multi_viewport{};
|
bool support_multi_viewport{};
|
||||||
bool support_geometry_streams{};
|
bool support_geometry_streams{};
|
||||||
bool support_sampled_image_array_nonuniform_indexing{};
|
bool support_sampled_image_array_nonuniform_indexing{};
|
||||||
|
bool support_storage_image_array_nonuniform_indexing{};
|
||||||
|
bool support_uniform_texel_buffer_array_nonuniform_indexing{};
|
||||||
|
bool support_storage_texel_buffer_array_nonuniform_indexing{};
|
||||||
|
|
||||||
bool warp_size_potentially_larger_than_guest{};
|
bool warp_size_potentially_larger_than_guest{};
|
||||||
|
|
||||||
|
|||||||
@@ -121,12 +121,21 @@ public:
|
|||||||
return size_bytes;
|
return size_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 getWriteTick() const noexcept {
|
||||||
|
return write_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWriteTick(u64 write_tick_) {
|
||||||
|
write_tick = write_tick_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VAddr cpu_addr = 0;
|
VAddr cpu_addr = 0;
|
||||||
BufferFlagBits flags{};
|
BufferFlagBits flags{};
|
||||||
int stream_score = 0;
|
int stream_score = 0;
|
||||||
size_t lru_id = SIZE_MAX;
|
size_t lru_id = SIZE_MAX;
|
||||||
size_t size_bytes = 0;
|
size_t size_bytes = 0;
|
||||||
|
u64 write_tick = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
@@ -175,9 +175,71 @@ std::optional<VideoCore::RasterizerDownloadArea> BufferCache<P>::GetFlushArea(DA
|
|||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::DownloadMemory(DAddr device_addr, u64 size) {
|
void BufferCache<P>::DownloadMemory(DAddr device_addr, u64 size) {
|
||||||
ForEachBufferInRange(device_addr, size, [&](BufferId, Buffer& buffer) {
|
if constexpr (!USE_MEMORY_MAPS) {
|
||||||
DownloadBufferMemory(buffer, device_addr, size);
|
std::scoped_lock lock{mutex};
|
||||||
|
ForEachBufferInRange(device_addr, size, [&](BufferId, Buffer& buffer) {
|
||||||
|
DownloadBufferMemory(buffer, device_addr, size);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::container::small_vector<std::pair<BufferCopy, BufferId>, 8> downloads;
|
||||||
|
u64 total_size_bytes = 0;
|
||||||
|
u64 largest_copy = 0;
|
||||||
|
|
||||||
|
std::unique_lock lock{mutex};
|
||||||
|
ForEachBufferInRange(device_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
|
||||||
|
memory_tracker.ForEachDownloadRangeAndClear(
|
||||||
|
device_addr, size, [&](u64 device_addr_out, u64 range_size) {
|
||||||
|
const DAddr buffer_addr = buffer.CpuAddr();
|
||||||
|
const auto add_download = [&](DAddr start, DAddr end) {
|
||||||
|
const u64 new_offset = start - buffer_addr;
|
||||||
|
const u64 new_size = end - start;
|
||||||
|
downloads.push_back({
|
||||||
|
BufferCopy{
|
||||||
|
.src_offset = new_offset,
|
||||||
|
.dst_offset = total_size_bytes,
|
||||||
|
.size = new_size,
|
||||||
|
},
|
||||||
|
buffer_id,
|
||||||
|
});
|
||||||
|
constexpr u64 align = 64ULL;
|
||||||
|
constexpr u64 mask = ~(align - 1ULL);
|
||||||
|
total_size_bytes += (new_size + align - 1) & mask;
|
||||||
|
largest_copy = (std::max)(largest_copy, new_size);
|
||||||
|
};
|
||||||
|
gpu_modified_ranges.ForEachInRange(device_addr_out, range_size, add_download);
|
||||||
|
ClearDownload(device_addr_out, range_size);
|
||||||
|
gpu_modified_ranges.Subtract(device_addr_out, range_size);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
if (total_size_bytes == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
|
||||||
|
boost::container::small_vector<BufferCopy, 8> writebacks;
|
||||||
|
runtime.PreCopyBarrier();
|
||||||
|
for (auto& [copy, buffer_id] : downloads) {
|
||||||
|
copy.dst_offset += download_staging.offset;
|
||||||
|
Buffer& buffer = slot_buffers[buffer_id];
|
||||||
|
buffer.MarkUsage(copy.src_offset, copy.size);
|
||||||
|
const std::array copies{copy};
|
||||||
|
runtime.CopyBuffer(download_staging.buffer, buffer, copies, false);
|
||||||
|
BufferCopy writeback{copy};
|
||||||
|
writeback.src_offset = static_cast<u64>(buffer.CpuAddr()) + copy.src_offset;
|
||||||
|
writebacks.push_back(writeback);
|
||||||
|
}
|
||||||
|
runtime.PostCopyBarrier();
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
runtime.Finish();
|
||||||
|
const u8* const base = download_staging.mapped_span.data();
|
||||||
|
for (const BufferCopy& writeback : writebacks) {
|
||||||
|
const u64 staging_offset = writeback.dst_offset - download_staging.offset;
|
||||||
|
device_memory.WriteBlockUnsafe(static_cast<DAddr>(writeback.src_offset),
|
||||||
|
base + staging_offset, writeback.size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
@@ -214,7 +276,7 @@ bool BufferCache<P>::DMACopy(GPUVAddr src_address, GPUVAddr dest_address, u64 am
|
|||||||
auto& src_buffer = slot_buffers[buffer_a];
|
auto& src_buffer = slot_buffers[buffer_a];
|
||||||
auto& dest_buffer = slot_buffers[buffer_b];
|
auto& dest_buffer = slot_buffers[buffer_b];
|
||||||
SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
|
SynchronizeBuffer(src_buffer, *cpu_src_address, static_cast<u32>(amount));
|
||||||
SynchronizeBuffer(dest_buffer, *cpu_dest_address, static_cast<u32>(amount));
|
memory_tracker.UnmarkRegionAsCpuModified(*cpu_dest_address, static_cast<u32>(amount));
|
||||||
std::array copies{BufferCopy{
|
std::array copies{BufferCopy{
|
||||||
.src_offset = src_buffer.Offset(*cpu_src_address),
|
.src_offset = src_buffer.Offset(*cpu_src_address),
|
||||||
.dst_offset = dest_buffer.Offset(*cpu_dest_address),
|
.dst_offset = dest_buffer.Offset(*cpu_dest_address),
|
||||||
@@ -673,32 +735,44 @@ void BufferCache<P>::PopAsyncFlushes() {
|
|||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::PopAsyncBuffers() {
|
void BufferCache<P>::PopAsyncBuffers() {
|
||||||
if (async_buffers.empty()) {
|
struct Writeback {
|
||||||
return;
|
DAddr addr;
|
||||||
}
|
const u8* src;
|
||||||
if (!async_buffers.front().has_value()) {
|
u64 size;
|
||||||
|
};
|
||||||
|
boost::container::small_vector<Writeback, 8> writebacks;
|
||||||
|
{
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
if (async_buffers.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!async_buffers.front().has_value()) {
|
||||||
|
async_buffers.pop_front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& downloads = pending_downloads.front();
|
||||||
|
auto& async_buffer = async_buffers.front();
|
||||||
|
const u8* base = async_buffer->mapped_span.data();
|
||||||
|
const size_t base_offset = async_buffer->offset;
|
||||||
|
for (const auto& copy : downloads) {
|
||||||
|
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
||||||
|
const u64 dst_offset = copy.dst_offset - base_offset;
|
||||||
|
const u8* read_mapped_memory = base + dst_offset;
|
||||||
|
async_downloads.ForEachInRange(device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
|
||||||
|
writebacks.push_back(
|
||||||
|
{start, &read_mapped_memory[start - device_addr], end - start});
|
||||||
|
});
|
||||||
|
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
||||||
|
gpu_modified_ranges.Subtract(start, end - start);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async_buffers_death_ring.emplace_back(*async_buffer);
|
||||||
async_buffers.pop_front();
|
async_buffers.pop_front();
|
||||||
return;
|
pending_downloads.pop_front();
|
||||||
}
|
}
|
||||||
auto& downloads = pending_downloads.front();
|
for (const auto& wb : writebacks) {
|
||||||
auto& async_buffer = async_buffers.front();
|
device_memory.WriteBlockUnsafe(wb.addr, wb.src, wb.size);
|
||||||
u8* base = async_buffer->mapped_span.data();
|
|
||||||
const size_t base_offset = async_buffer->offset;
|
|
||||||
for (const auto& copy : downloads) {
|
|
||||||
const DAddr device_addr = static_cast<DAddr>(copy.src_offset);
|
|
||||||
const u64 dst_offset = copy.dst_offset - base_offset;
|
|
||||||
const u8* read_mapped_memory = base + dst_offset;
|
|
||||||
async_downloads.ForEachInRange(device_addr, copy.size, [&](DAddr start, DAddr end, s32) {
|
|
||||||
device_memory.WriteBlockUnsafe(start, &read_mapped_memory[start - device_addr],
|
|
||||||
end - start);
|
|
||||||
});
|
|
||||||
async_downloads.Subtract(device_addr, copy.size, [&](DAddr start, DAddr end) {
|
|
||||||
gpu_modified_ranges.Subtract(start, end - start);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
async_buffers_death_ring.emplace_back(*async_buffer);
|
|
||||||
async_buffers.pop_front();
|
|
||||||
pending_downloads.pop_front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
@@ -1430,6 +1504,10 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
|
|||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) {
|
void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) {
|
||||||
|
if constexpr (!IS_OPENGL) {
|
||||||
|
Buffer& buffer = slot_buffers[buffer_id];
|
||||||
|
buffer.setWriteTick(runtime.CurrentTick());
|
||||||
|
}
|
||||||
memory_tracker.MarkRegionAsGpuModified(device_addr, size);
|
memory_tracker.MarkRegionAsGpuModified(device_addr, size);
|
||||||
gpu_modified_ranges.Add(device_addr, size);
|
gpu_modified_ranges.Add(device_addr, size);
|
||||||
uncommitted_gpu_modified_ranges.Add(device_addr, size);
|
uncommitted_gpu_modified_ranges.Add(device_addr, size);
|
||||||
@@ -1442,16 +1520,32 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
|
|||||||
}
|
}
|
||||||
const u64 page = device_addr >> CACHING_PAGEBITS;
|
const u64 page = device_addr >> CACHING_PAGEBITS;
|
||||||
const BufferId buffer_id = page_table[page];
|
const BufferId buffer_id = page_table[page];
|
||||||
if (!buffer_id) {
|
if (buffer_id) {
|
||||||
return CreateBuffer(device_addr, size);
|
Buffer& buffer = slot_buffers[buffer_id];
|
||||||
}
|
WaitForGpuFenceIfNeeded(buffer);
|
||||||
const Buffer& buffer = slot_buffers[buffer_id];
|
if (buffer.IsInBounds(device_addr, size)) {
|
||||||
if (buffer.IsInBounds(device_addr, size)) {
|
return buffer_id;
|
||||||
return buffer_id;
|
}
|
||||||
}
|
}
|
||||||
return CreateBuffer(device_addr, size);
|
return CreateBuffer(device_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class P>
|
||||||
|
void BufferCache<P>::WaitForGpuFenceIfNeeded(Buffer& buffer) {
|
||||||
|
if constexpr (!IS_OPENGL) {
|
||||||
|
const bool gpu_fence_accurate = Settings::IsGPUFenceBehaviorAccurate();
|
||||||
|
const bool gpu_fence_strict = Settings::IsGPUFenceBehaviorStrict();
|
||||||
|
if (gpu_fence_accurate || gpu_fence_strict) {
|
||||||
|
const u64 gpu_tick_delay = gpu_fence_strict ? 0 : 3;
|
||||||
|
const u64 buffer_tick = buffer.getWriteTick();
|
||||||
|
const u64 gpu_tick = runtime.KnownGpuTick();
|
||||||
|
if (buffer_tick > gpu_tick + gpu_tick_delay) {
|
||||||
|
runtime.Wait(buffer_tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr,
|
typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr,
|
||||||
u32 wanted_size) {
|
u32 wanted_size) {
|
||||||
@@ -1634,17 +1728,6 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
|
|||||||
if (total_size_bytes == 0) {
|
if (total_size_bytes == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
|
|
||||||
u64 min_offset = (std::numeric_limits<u64>::max)();
|
|
||||||
u64 max_offset = 0;
|
|
||||||
for (const auto& copy : upload_copies) {
|
|
||||||
min_offset = (std::min)(min_offset, copy.dst_offset);
|
|
||||||
max_offset = (std::max)(max_offset, copy.dst_offset + copy.size);
|
|
||||||
}
|
|
||||||
const DAddr sync_addr = buffer.CpuAddr() + min_offset;
|
|
||||||
const u64 sync_size = max_offset - min_offset;
|
|
||||||
DownloadBufferMemory(buffer, sync_addr, sync_size);
|
|
||||||
}
|
|
||||||
const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
|
const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
|
||||||
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
|
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
|
||||||
any_buffer_uploaded = true;
|
any_buffer_uploaded = true;
|
||||||
@@ -1679,6 +1762,9 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
|
|||||||
if (immediate_buffer.empty()) {
|
if (immediate_buffer.empty()) {
|
||||||
immediate_buffer = ImmediateBuffer(largest_copy);
|
immediate_buffer = ImmediateBuffer(largest_copy);
|
||||||
}
|
}
|
||||||
|
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
|
||||||
|
DownloadBufferMemory(buffer, device_addr, copy.size);
|
||||||
|
}
|
||||||
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
|
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
|
||||||
upload_span = immediate_buffer.subspan(0, copy.size);
|
upload_span = immediate_buffer.subspan(0, copy.size);
|
||||||
}
|
}
|
||||||
@@ -1697,6 +1783,9 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
|
|||||||
for (BufferCopy& copy : copies) {
|
for (BufferCopy& copy : copies) {
|
||||||
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
|
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
|
||||||
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
||||||
|
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
|
||||||
|
DownloadBufferMemory(buffer, device_addr, copy.size);
|
||||||
|
}
|
||||||
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
|
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
|
||||||
// Apply the staging offset
|
// Apply the staging offset
|
||||||
copy.src_offset += upload_staging.offset;
|
copy.src_offset += upload_staging.offset;
|
||||||
|
|||||||
@@ -416,6 +416,8 @@ private:
|
|||||||
|
|
||||||
[[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size);
|
[[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size);
|
||||||
|
|
||||||
|
void WaitForGpuFenceIfNeeded(Buffer& buffer);
|
||||||
|
|
||||||
[[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size);
|
[[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size);
|
||||||
|
|
||||||
void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
|
void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ bool DmaPusher::Step() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (header.size > 0) {
|
if (header.size > 0) {
|
||||||
if (Settings::IsDMALevelDefault() ? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh()) : Settings::IsDMALevelSafe()) {
|
const bool use_safe = Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe();
|
||||||
|
if (use_safe) {
|
||||||
Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::SafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers);
|
Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::SafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers);
|
||||||
ProcessCommands(headers);
|
ProcessCommands(headers);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -72,16 +72,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SignalFence(std::function<void()>&& func) {
|
void SignalFence(std::function<void()>&& func) {
|
||||||
|
const bool delay_fence = Settings::IsGPUFenceBehaviorDefault() ? Settings::IsGPULevelHigh() : Settings::IsGPUFenceBehaviorBalanced() || Settings::IsGPUFenceBehaviorAccurate() || Settings::IsGPUFenceBehaviorStrict();
|
||||||
|
const bool should_flush = ShouldFlush();
|
||||||
if constexpr (!can_async_check) {
|
if constexpr (!can_async_check) {
|
||||||
TryReleasePendingFences<false>();
|
TryReleasePendingFences<false>();
|
||||||
}
|
}
|
||||||
const bool should_flush = ShouldFlush();
|
|
||||||
const bool antiflicker_toggled = Settings::values.antiflicker.GetValue();
|
|
||||||
const bool delay_fence = Settings::IsGPULevelHigh() ||
|
|
||||||
(Settings::IsGPULevelMedium() && should_flush) ||
|
|
||||||
antiflicker_toggled;
|
|
||||||
CommitAsyncFlushes();
|
CommitAsyncFlushes();
|
||||||
TFence new_fence = CreateFence(!should_flush && !antiflicker_toggled);
|
TFence new_fence = CreateFence(!should_flush);
|
||||||
if constexpr (can_async_check) {
|
if constexpr (can_async_check) {
|
||||||
guard.lock();
|
guard.lock();
|
||||||
}
|
}
|
||||||
@@ -94,9 +91,6 @@ public:
|
|||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
fences.push(std::move(new_fence));
|
fences.push(std::move(new_fence));
|
||||||
if (should_flush) {
|
|
||||||
rasterizer.FlushCommands();
|
|
||||||
}
|
|
||||||
if constexpr (can_async_check) {
|
if constexpr (can_async_check) {
|
||||||
guard.unlock();
|
guard.unlock();
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
@@ -241,10 +235,10 @@ private:
|
|||||||
|
|
||||||
void PopAsyncFlushes() {
|
void PopAsyncFlushes() {
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
std::scoped_lock lock{texture_cache.mutex};
|
||||||
texture_cache.PopAsyncFlushes();
|
texture_cache.PopAsyncFlushes();
|
||||||
buffer_cache.PopAsyncFlushes();
|
|
||||||
}
|
}
|
||||||
|
buffer_cache.PopAsyncFlushes();
|
||||||
query_cache.PopAsyncFlushes();
|
query_cache.PopAsyncFlushes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ set(SHADER_FILES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/astc_decoder.comp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_float.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_float.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_2d.comp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/blit_color_msaa.frag
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/blit_depth_msaa.frag
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/blit_depth_stencil_msaa.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d.comp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d_bcn.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/block_linear_unswizzle_3d_bcn.comp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_abgr8_to_d24s8.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_abgr8_to_d24s8.frag
|
||||||
@@ -26,7 +29,9 @@ set(SHADER_FILES
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_depth_to_float.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_depth_to_float.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_float_to_depth.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_float_to_depth.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.comp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_msaa_to_non_msaa.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.comp
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.comp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_non_msaa_to_msaa.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/convert_s8d24_to_abgr8.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/convert_s8d24_to_abgr8.frag
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/full_screen_triangle.vert
|
${CMAKE_CURRENT_SOURCE_DIR}/full_screen_triangle.vert
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/fxaa.frag
|
${CMAKE_CURRENT_SOURCE_DIR}/fxaa.frag
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2DMS tex;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 texcoord;
|
||||||
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
color = texelFetch(tex, ivec2(texcoord), gl_SampleID);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2DMS depth_tex;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 texcoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragDepth = texelFetch(depth_tex, ivec2(texcoord), 0).r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#version 450 core
|
||||||
|
#extension GL_ARB_shader_stencil_export : require
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2DMS depth_tex;
|
||||||
|
layout(binding = 1) uniform usampler2DMS stencil_tex;
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 texcoord;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragDepth = texelFetch(depth_tex, ivec2(texcoord), 0).r;
|
||||||
|
gl_FragStencilRefARB = int(texelFetch(stencil_tex, ivec2(texcoord), 0).r);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2DMS msaa_in;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
ivec2 dst_offset;
|
||||||
|
ivec2 src_offset;
|
||||||
|
ivec2 scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 frag_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const ivec2 coord = ivec2(gl_FragCoord.xy) - dst_offset + src_offset;
|
||||||
|
const ivec2 msaa_coord = coord / scale;
|
||||||
|
const ivec2 sample_offset = coord % scale;
|
||||||
|
const int sample_id = sample_offset.x + scale.x * sample_offset.y;
|
||||||
|
frag_color = texelFetch(msaa_in, msaa_coord, sample_id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#version 450 core
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D img_in;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
ivec2 dst_offset;
|
||||||
|
ivec2 src_offset;
|
||||||
|
ivec2 scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 frag_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const ivec2 msaa_coord = ivec2(gl_FragCoord.xy) - dst_offset;
|
||||||
|
const ivec2 sample_offset = ivec2(gl_SampleID % scale.x, gl_SampleID / scale.x);
|
||||||
|
const ivec2 coord = msaa_coord * scale + sample_offset + src_offset;
|
||||||
|
frag_color = texelFetch(img_in, coord, 0);
|
||||||
|
}
|
||||||
@@ -260,7 +260,7 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
|
|||||||
};
|
};
|
||||||
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
|
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
|
||||||
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
|
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
|
||||||
bool is_synced = !Settings::IsGPULevelHigh() && is_fence;
|
bool is_synced = (Settings::IsGPUFenceBehaviorDefault() ? !Settings::IsGPULevelHigh() : !Settings::IsGPUFenceBehaviorBalanced() && !Settings::IsGPUFenceBehaviorAccurate() && !Settings::IsGPUFenceBehaviorStrict()) && is_fence;
|
||||||
std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,
|
std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,
|
||||||
pointer, pointer_timestamp] {
|
pointer, pointer_timestamp] {
|
||||||
if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
|
if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
|
||||||
|
|||||||
@@ -485,7 +485,6 @@ void RasterizerOpenGL::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType
|
|||||||
texture_cache.DownloadMemory(addr, size);
|
texture_cache.DownloadMemory(addr, size);
|
||||||
}
|
}
|
||||||
if ((True(which & VideoCommon::CacheType::BufferCache))) {
|
if ((True(which & VideoCommon::CacheType::BufferCache))) {
|
||||||
std::scoped_lock lock{buffer_cache.mutex};
|
|
||||||
buffer_cache.DownloadMemory(addr, size);
|
buffer_cache.DownloadMemory(addr, size);
|
||||||
}
|
}
|
||||||
if ((True(which & VideoCommon::CacheType::QueryCache))) {
|
if ((True(which & VideoCommon::CacheType::QueryCache))) {
|
||||||
|
|||||||
@@ -8,14 +8,20 @@
|
|||||||
|
|
||||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||||
|
|
||||||
|
#include "common/div_ceil.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
|
#include "video_core/host_shaders/blit_color_float_frag_spv.h"
|
||||||
|
#include "video_core/host_shaders/blit_color_msaa_frag_spv.h"
|
||||||
|
#include "video_core/host_shaders/blit_depth_msaa_frag_spv.h"
|
||||||
|
#include "video_core/host_shaders/blit_depth_stencil_msaa_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
|
#include "video_core/host_shaders/convert_abgr8_to_d24s8_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_abgr8_to_d32f_frag_spv.h"
|
#include "video_core/host_shaders/convert_abgr8_to_d32f_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
|
#include "video_core/host_shaders/convert_d24s8_to_abgr8_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h"
|
#include "video_core/host_shaders/convert_d32f_to_abgr8_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
|
#include "video_core/host_shaders/convert_depth_to_float_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
|
#include "video_core/host_shaders/convert_float_to_depth_frag_spv.h"
|
||||||
|
#include "video_core/host_shaders/convert_msaa_to_non_msaa_frag_spv.h"
|
||||||
|
#include "video_core/host_shaders/convert_non_msaa_to_msaa_frag_spv.h"
|
||||||
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
|
#include "video_core/host_shaders/convert_s8d24_to_abgr8_frag_spv.h"
|
||||||
#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
|
#include "video_core/host_shaders/full_screen_triangle_vert_spv.h"
|
||||||
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
|
#include "video_core/host_shaders/vulkan_blit_depth_stencil_frag_spv.h"
|
||||||
@@ -24,11 +30,13 @@
|
|||||||
#include "video_core/host_shaders/vulkan_depthstencil_clear_frag_spv.h"
|
#include "video_core/host_shaders/vulkan_depthstencil_clear_frag_spv.h"
|
||||||
#include "video_core/renderer_vulkan/blit_image.h"
|
#include "video_core/renderer_vulkan/blit_image.h"
|
||||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_render_pass_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
||||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||||
#include "video_core/surface.h"
|
#include "video_core/surface.h"
|
||||||
|
#include "video_core/texture_cache/samples_helper.h"
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
@@ -74,6 +82,12 @@ struct PushConstants {
|
|||||||
std::array<float, 2> tex_offset;
|
std::array<float, 2> tex_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MSAACopyPushConstants {
|
||||||
|
std::array<s32, 2> dst_offset;
|
||||||
|
std::array<s32, 2> src_offset;
|
||||||
|
std::array<s32, 2> scale;
|
||||||
|
};
|
||||||
|
|
||||||
template <u32 binding>
|
template <u32 binding>
|
||||||
inline constexpr VkDescriptorSetLayoutBinding TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING{
|
inline constexpr VkDescriptorSetLayoutBinding TEXTURE_DESCRIPTOR_SET_LAYOUT_BINDING{
|
||||||
.binding = binding,
|
.binding = binding,
|
||||||
@@ -241,6 +255,21 @@ constexpr VkPipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_STENCIL_STATE_CRE
|
|||||||
.maxDepthBounds = 0.0f,
|
.maxDepthBounds = 0.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr VkPipelineDepthStencilStateCreateInfo PIPELINE_DEPTH_ONLY_STATE_CREATE_INFO{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.depthTestEnable = VK_TRUE,
|
||||||
|
.depthWriteEnable = VK_TRUE,
|
||||||
|
.depthCompareOp = VK_COMPARE_OP_ALWAYS,
|
||||||
|
.depthBoundsTestEnable = VK_FALSE,
|
||||||
|
.stencilTestEnable = VK_FALSE,
|
||||||
|
.front = VkStencilOpState{},
|
||||||
|
.back = VkStencilOpState{},
|
||||||
|
.minDepthBounds = 0.0f,
|
||||||
|
.maxDepthBounds = 0.0f,
|
||||||
|
};
|
||||||
|
|
||||||
template <VkFilter filter>
|
template <VkFilter filter>
|
||||||
inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
|
inline constexpr VkSamplerCreateInfo SAMPLER_CREATE_INFO{
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||||
@@ -474,8 +503,52 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkSampleCountFlagBits SampleCountFlag(u32 num_samples) {
|
||||||
|
switch (num_samples) {
|
||||||
|
case 2:
|
||||||
|
return VK_SAMPLE_COUNT_2_BIT;
|
||||||
|
case 4:
|
||||||
|
return VK_SAMPLE_COUNT_4_BIT;
|
||||||
|
case 8:
|
||||||
|
return VK_SAMPLE_COUNT_8_BIT;
|
||||||
|
case 16:
|
||||||
|
return VK_SAMPLE_COUNT_16_BIT;
|
||||||
|
default:
|
||||||
|
return VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] vk::ImageView MakeMSAACopyView(const vk::Device& device, VkImage image,
|
||||||
|
VkFormat format, u32 base_level) {
|
||||||
|
return device.CreateImageView(VkImageViewCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.image = image,
|
||||||
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||||
|
.format = format,
|
||||||
|
.components{
|
||||||
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||||
|
},
|
||||||
|
.subresourceRange{
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = base_level,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||||
const VkRenderPass render_pass = framebuffer->RenderPass();
|
const VkRenderPass render_pass = framebuffer->RenderPass();
|
||||||
|
if (!render_pass) {
|
||||||
|
framebuffer->BeginRendering(cmdbuf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
const VkExtent2D render_area = framebuffer->RenderArea();
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
const VkRenderPassBeginInfo renderpass_bi{
|
const VkRenderPassBeginInfo renderpass_bi{
|
||||||
@@ -492,6 +565,31 @@ void BeginRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer)
|
|||||||
};
|
};
|
||||||
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EndRenderPass(vk::CommandBuffer& cmdbuf, const Framebuffer* framebuffer) {
|
||||||
|
if (framebuffer->RenderPass()) {
|
||||||
|
cmdbuf.EndRenderPass();
|
||||||
|
} else {
|
||||||
|
cmdbuf.EndRendering();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkPipelineRenderingCreateInfo MakePipelineRenderingCreateInfo(
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
|
return VkPipelineRenderingCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = framebuffer->NumColorAttachments(),
|
||||||
|
.pColorAttachmentFormats = framebuffer->ColorAttachmentFormats().data(),
|
||||||
|
.depthAttachmentFormat = framebuffer->HasAspectDepthBit()
|
||||||
|
? framebuffer->DepthAttachmentFormat()
|
||||||
|
: VK_FORMAT_UNDEFINED,
|
||||||
|
.stencilAttachmentFormat = framebuffer->HasAspectStencilBit()
|
||||||
|
? framebuffer->DepthAttachmentFormat()
|
||||||
|
: VK_FORMAT_UNDEFINED,
|
||||||
|
};
|
||||||
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
||||||
@@ -514,11 +612,19 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
|||||||
PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
|
PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstants)>))),
|
||||||
clear_color_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
|
clear_color_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
|
||||||
nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
|
nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
|
||||||
|
msaa_copy_pipeline_layout(device.GetLogical().CreatePipelineLayout(PipelineLayoutCreateInfo(
|
||||||
|
one_texture_set_layout.address(),
|
||||||
|
PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(MSAACopyPushConstants)>))),
|
||||||
full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
|
full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
|
||||||
blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
|
blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
|
||||||
|
blit_color_msaa_frag(BuildShader(device, BLIT_COLOR_MSAA_FRAG_SPV)),
|
||||||
blit_depth_stencil_frag(device.IsExtShaderStencilExportSupported()
|
blit_depth_stencil_frag(device.IsExtShaderStencilExportSupported()
|
||||||
? BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)
|
? BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)
|
||||||
: vk::ShaderModule{}),
|
: vk::ShaderModule{}),
|
||||||
|
blit_depth_msaa_frag(BuildShader(device, BLIT_DEPTH_MSAA_FRAG_SPV)),
|
||||||
|
blit_depth_stencil_msaa_frag(device.IsExtShaderStencilExportSupported()
|
||||||
|
? BuildShader(device, BLIT_DEPTH_STENCIL_MSAA_FRAG_SPV)
|
||||||
|
: vk::ShaderModule{}),
|
||||||
clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
|
clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
|
||||||
clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
|
clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
|
||||||
clear_stencil_frag(BuildShader(device, VULKAN_DEPTHSTENCIL_CLEAR_FRAG_SPV)),
|
clear_stencil_frag(BuildShader(device, VULKAN_DEPTHSTENCIL_CLEAR_FRAG_SPV)),
|
||||||
@@ -531,6 +637,8 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
|||||||
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
|
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
|
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
|
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
|
||||||
|
convert_msaa_to_non_msaa_frag(BuildShader(device, CONVERT_MSAA_TO_NON_MSAA_FRAG_SPV)),
|
||||||
|
convert_non_msaa_to_msaa_frag(BuildShader(device, CONVERT_NON_MSAA_TO_MSAA_FRAG_SPV)),
|
||||||
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
|
linear_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_LINEAR>)),
|
||||||
nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {}
|
nearest_sampler(device.GetLogical().CreateSampler(SAMPLER_CREATE_INFO<VK_FILTER_NEAREST>)) {}
|
||||||
|
|
||||||
@@ -544,10 +652,12 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = operation,
|
.operation = operation,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
const VkSampler sampler = is_linear ? *linear_sampler : *nearest_sampler;
|
||||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key, dst_framebuffer);
|
||||||
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
||||||
|
|
||||||
RecordShaderReadBarrier(scheduler, src_image_view);
|
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||||
@@ -572,9 +682,11 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
.operation = Tegra::Engines::Fermi2D::Operation::SrcCopy,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key, dst_framebuffer);
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
|
scheduler.Record([this, dst_framebuffer, src_image_view, src_image, src_sampler, dst_region,
|
||||||
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
|
src_region, src_size, pipeline, layout](vk::CommandBuffer cmdbuf) {
|
||||||
@@ -587,10 +699,76 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
|||||||
nullptr);
|
nullptr);
|
||||||
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
BindBlitState(cmdbuf, layout, dst_region, src_region, src_size);
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
cmdbuf.EndRenderPass();
|
EndRenderPass(cmdbuf, dst_framebuffer);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::BlitColorMSAA(const Framebuffer* dst_framebuffer,
|
||||||
|
const ImageView& src_image_view, const Region2D& dst_region,
|
||||||
|
const Region2D& src_region) {
|
||||||
|
const BlitMSAAPipelineKey key{
|
||||||
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
|
.samples = dst_framebuffer->Samples(),
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
|
};
|
||||||
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
|
const VkSampler sampler = *nearest_sampler;
|
||||||
|
const VkPipeline pipeline = FindOrEmplaceBlitColorMSAAPipeline(key, dst_framebuffer);
|
||||||
|
const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D);
|
||||||
|
|
||||||
|
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||||
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
|
scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler,
|
||||||
|
src_view](vk::CommandBuffer cmdbuf) {
|
||||||
|
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||||
|
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view);
|
||||||
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
|
nullptr);
|
||||||
|
BindBlitState(cmdbuf, layout, dst_region, src_region);
|
||||||
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
|
});
|
||||||
|
scheduler.InvalidateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::ResolveDepthStencil(const Framebuffer* dst_framebuffer,
|
||||||
|
ImageView& src_image_view, const Region2D& dst_region,
|
||||||
|
const Region2D& src_region) {
|
||||||
|
const bool resolve_stencil =
|
||||||
|
dst_framebuffer->HasAspectStencilBit() && device.IsExtShaderStencilExportSupported();
|
||||||
|
const VkPipeline pipeline =
|
||||||
|
FindOrEmplaceResolveDepthStencilPipeline(dst_framebuffer, resolve_stencil);
|
||||||
|
const VkPipelineLayout layout =
|
||||||
|
resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout;
|
||||||
|
const VkSampler sampler = *nearest_sampler;
|
||||||
|
const VkImageView src_depth_view = src_image_view.DepthView();
|
||||||
|
const VkImageView src_stencil_view =
|
||||||
|
resolve_stencil ? src_image_view.StencilView() : VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
RecordShaderReadBarrier(scheduler, src_image_view);
|
||||||
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
|
scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler, src_depth_view,
|
||||||
|
src_stencil_view, resolve_stencil](vk::CommandBuffer cmdbuf) {
|
||||||
|
if (resolve_stencil) {
|
||||||
|
const VkDescriptorSet descriptor_set = two_textures_descriptor_allocator.Commit();
|
||||||
|
UpdateTwoTexturesDescriptorSet(device, descriptor_set, sampler, src_depth_view,
|
||||||
|
src_stencil_view);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
|
nullptr);
|
||||||
|
} else {
|
||||||
|
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||||
|
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_depth_view);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
|
BindBlitState(cmdbuf, layout, dst_region, src_region);
|
||||||
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
|
});
|
||||||
|
scheduler.InvalidateState();
|
||||||
|
}
|
||||||
|
|
||||||
void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view,
|
ImageView& src_image_view,
|
||||||
const Region2D& dst_region, const Region2D& src_region,
|
const Region2D& dst_region, const Region2D& src_region,
|
||||||
@@ -604,10 +782,12 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = operation,
|
.operation = operation,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipelineLayout layout = *two_textures_pipeline_layout;
|
const VkPipelineLayout layout = *two_textures_pipeline_layout;
|
||||||
const VkSampler sampler = *nearest_sampler;
|
const VkSampler sampler = *nearest_sampler;
|
||||||
const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceDepthStencilPipeline(key, dst_framebuffer);
|
||||||
const VkImageView src_depth_view = src_image_view.DepthView();
|
const VkImageView src_depth_view = src_image_view.DepthView();
|
||||||
const VkImageView src_stencil_view = src_image_view.StencilView();
|
const VkImageView src_stencil_view = src_image_view.StencilView();
|
||||||
|
|
||||||
@@ -629,25 +809,25 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
|||||||
|
|
||||||
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD32ToR32(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer->RenderPass());
|
ConvertDepthToColorPipeline(convert_d32_to_r32_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_d32_to_r32_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertR32ToD32(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer->RenderPass());
|
ConvertColorToDepthPipeline(convert_r32_to_d32_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_r32_to_d32_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD16ToR16(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer->RenderPass());
|
ConvertDepthToColorPipeline(convert_d16_to_r16_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_d16_to_r16_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer->RenderPass());
|
ConvertColorToDepthPipeline(convert_r16_to_d16_pipeline, dst_framebuffer);
|
||||||
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_r16_to_d16_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,35 +838,35 @@ void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
|
|||||||
LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping");
|
LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer,
|
||||||
convert_abgr8_to_d24s8_frag);
|
convert_abgr8_to_d24s8_frag);
|
||||||
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertABGR8ToD32F(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineDepthTargetEx(convert_abgr8_to_d32f_pipeline, dst_framebuffer,
|
||||||
convert_abgr8_to_d32f_frag);
|
convert_abgr8_to_d32f_frag);
|
||||||
Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_abgr8_to_d32f_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD32FToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_d32f_to_abgr8_pipeline, dst_framebuffer,
|
||||||
convert_d32f_to_abgr8_frag);
|
convert_d32f_to_abgr8_frag);
|
||||||
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
ConvertDepthStencil(*convert_d32f_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertD24S8ToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_d24s8_to_abgr8_pipeline, dst_framebuffer,
|
||||||
convert_d24s8_to_abgr8_frag);
|
convert_d24s8_to_abgr8_frag);
|
||||||
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
ConvertDepthStencil(*convert_d24s8_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view) {
|
ImageView& src_image_view) {
|
||||||
ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineColorTargetEx(convert_s8d24_to_abgr8_pipeline, dst_framebuffer,
|
||||||
convert_s8d24_to_abgr8_frag);
|
convert_s8d24_to_abgr8_frag);
|
||||||
ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
ConvertDepthStencil(*convert_s8d24_to_abgr8_pipeline, dst_framebuffer, src_image_view);
|
||||||
}
|
}
|
||||||
@@ -697,8 +877,10 @@ void BlitImageHelper::ClearColor(const Framebuffer* dst_framebuffer, u8 color_ma
|
|||||||
const BlitImagePipelineKey key{
|
const BlitImagePipelineKey key{
|
||||||
.renderpass = dst_framebuffer->RenderPass(),
|
.renderpass = dst_framebuffer->RenderPass(),
|
||||||
.operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
|
.operation = Tegra::Engines::Fermi2D::Operation::BlendPremult,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceClearColorPipeline(key, dst_framebuffer);
|
||||||
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
||||||
scheduler.RequestRenderpass(dst_framebuffer);
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
scheduler.Record(
|
scheduler.Record(
|
||||||
@@ -724,8 +906,10 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
|
|||||||
.stencil_mask = stencil_mask,
|
.stencil_mask = stencil_mask,
|
||||||
.stencil_compare_mask = stencil_compare_mask,
|
.stencil_compare_mask = stencil_compare_mask,
|
||||||
.stencil_ref = stencil_ref,
|
.stencil_ref = stencil_ref,
|
||||||
|
.color_formats = dst_framebuffer->ColorAttachmentFormats(),
|
||||||
|
.depth_format = dst_framebuffer->DepthAttachmentFormat(),
|
||||||
};
|
};
|
||||||
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key);
|
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key, dst_framebuffer);
|
||||||
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
||||||
scheduler.RequestRenderpass(dst_framebuffer);
|
scheduler.RequestRenderpass(dst_framebuffer);
|
||||||
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
||||||
@@ -739,6 +923,174 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
|
|||||||
scheduler.InvalidateState();
|
scheduler.InvalidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_image,
|
||||||
|
VideoCore::Surface::PixelFormat dst_format, VkImage src_image,
|
||||||
|
VideoCore::Surface::PixelFormat src_format, u32 num_samples,
|
||||||
|
std::span<const VideoCommon::ImageCopy> copies,
|
||||||
|
bool msaa_to_non_msaa) {
|
||||||
|
while (!msaa_copy_resources.empty() && scheduler.IsFree(msaa_copy_resources.front().tick)) {
|
||||||
|
msaa_copy_resources.pop_front();
|
||||||
|
}
|
||||||
|
const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(static_cast<int>(num_samples));
|
||||||
|
const s32 scale_x = 1 << samples_x;
|
||||||
|
const s32 scale_y = 1 << samples_y;
|
||||||
|
const VkSampleCountFlagBits samples =
|
||||||
|
msaa_to_non_msaa ? VK_SAMPLE_COUNT_1_BIT : SampleCountFlag(num_samples);
|
||||||
|
RenderPassKey renderpass_key{};
|
||||||
|
renderpass_key.color_formats.fill(VideoCore::Surface::PixelFormat::Invalid);
|
||||||
|
renderpass_key.color_formats[0] = dst_format;
|
||||||
|
renderpass_key.depth_format = VideoCore::Surface::PixelFormat::Invalid;
|
||||||
|
renderpass_key.samples = samples;
|
||||||
|
const VkRenderPass renderpass = render_pass_cache.Get(renderpass_key);
|
||||||
|
const MSAACopyPipelineKey key{
|
||||||
|
.renderpass = renderpass,
|
||||||
|
.samples = samples,
|
||||||
|
.msaa_to_non_msaa = msaa_to_non_msaa,
|
||||||
|
};
|
||||||
|
const VkPipeline pipeline = FindOrEmplaceMSAACopyPipeline(key);
|
||||||
|
const VkPipelineLayout layout = *msaa_copy_pipeline_layout;
|
||||||
|
const VkSampler sampler = *nearest_sampler;
|
||||||
|
const VkFormat src_vk_format =
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, src_format).format;
|
||||||
|
const VkFormat dst_vk_format =
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, dst_format).format;
|
||||||
|
for (const VideoCommon::ImageCopy& copy : copies) {
|
||||||
|
ASSERT(copy.src_subresource.base_layer == 0);
|
||||||
|
ASSERT(copy.src_subresource.num_layers == 1);
|
||||||
|
ASSERT(copy.dst_subresource.base_layer == 0);
|
||||||
|
ASSERT(copy.dst_subresource.num_layers == 1);
|
||||||
|
vk::ImageView src_view =
|
||||||
|
MakeMSAACopyView(device.GetLogical(), src_image, src_vk_format,
|
||||||
|
static_cast<u32>(copy.src_subresource.base_level));
|
||||||
|
vk::ImageView dst_view =
|
||||||
|
MakeMSAACopyView(device.GetLogical(), dst_image, dst_vk_format,
|
||||||
|
static_cast<u32>(copy.dst_subresource.base_level));
|
||||||
|
const VkOffset2D dst_offset{copy.dst_offset.x, copy.dst_offset.y};
|
||||||
|
const VkExtent2D dst_extent{copy.extent.width, copy.extent.height};
|
||||||
|
const VkRect2D render_area{
|
||||||
|
.offset = dst_offset,
|
||||||
|
.extent = dst_extent,
|
||||||
|
};
|
||||||
|
vk::Framebuffer framebuffer = device.GetLogical().CreateFramebuffer(VkFramebufferCreateInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.renderPass = renderpass,
|
||||||
|
.attachmentCount = 1,
|
||||||
|
.pAttachments = dst_view.address(),
|
||||||
|
.width = static_cast<u32>(dst_offset.x) + dst_extent.width,
|
||||||
|
.height = static_cast<u32>(dst_offset.y) + dst_extent.height,
|
||||||
|
.layers = 1,
|
||||||
|
});
|
||||||
|
const MSAACopyPushConstants push_constants{
|
||||||
|
.dst_offset = {dst_offset.x, dst_offset.y},
|
||||||
|
.src_offset = {copy.src_offset.x, copy.src_offset.y},
|
||||||
|
.scale = {scale_x, scale_y},
|
||||||
|
};
|
||||||
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
|
scheduler.Record([this, pipeline, layout, sampler, renderpass,
|
||||||
|
framebuffer_handle = *framebuffer, src_view_handle = *src_view,
|
||||||
|
src = src_image, dst = dst_image, render_area,
|
||||||
|
push_constants](vk::CommandBuffer cmdbuf) {
|
||||||
|
constexpr VkImageSubresourceRange color_range{
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||||
|
};
|
||||||
|
const std::array pre_barriers{
|
||||||
|
VkImageMemoryBarrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||||
|
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = src,
|
||||||
|
.subresourceRange = color_range,
|
||||||
|
},
|
||||||
|
VkImageMemoryBarrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||||
|
VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||||
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = dst,
|
||||||
|
.subresourceRange = color_range,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
0, nullptr, nullptr, pre_barriers);
|
||||||
|
const VkRenderPassBeginInfo renderpass_bi{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.renderPass = renderpass,
|
||||||
|
.framebuffer = framebuffer_handle,
|
||||||
|
.renderArea = render_area,
|
||||||
|
.clearValueCount = 0,
|
||||||
|
.pClearValues = nullptr,
|
||||||
|
};
|
||||||
|
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
const VkDescriptorSet descriptor_set = one_texture_descriptor_allocator.Commit();
|
||||||
|
UpdateOneTextureDescriptorSet(device, descriptor_set, sampler, src_view_handle);
|
||||||
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
|
nullptr);
|
||||||
|
const VkViewport viewport{
|
||||||
|
.x = static_cast<float>(render_area.offset.x),
|
||||||
|
.y = static_cast<float>(render_area.offset.y),
|
||||||
|
.width = static_cast<float>(render_area.extent.width),
|
||||||
|
.height = static_cast<float>(render_area.extent.height),
|
||||||
|
.minDepth = 0.0f,
|
||||||
|
.maxDepth = 1.0f,
|
||||||
|
};
|
||||||
|
cmdbuf.SetViewport(0, viewport);
|
||||||
|
cmdbuf.SetScissor(0, render_area);
|
||||||
|
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, push_constants);
|
||||||
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
|
cmdbuf.EndRenderPass();
|
||||||
|
const VkImageMemoryBarrier post_barrier{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = dst,
|
||||||
|
.subresourceRange = color_range,
|
||||||
|
};
|
||||||
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
0, post_barrier);
|
||||||
|
});
|
||||||
|
msaa_copy_resources.push_back(MSAACopyResources{
|
||||||
|
.tick = scheduler.CurrentTick(),
|
||||||
|
.src_view = std::move(src_view),
|
||||||
|
.dst_view = std::move(dst_view),
|
||||||
|
.framebuffer = std::move(framebuffer),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
scheduler.InvalidateState();
|
||||||
|
}
|
||||||
|
|
||||||
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||||
@@ -829,12 +1181,14 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer
|
|||||||
scheduler.InvalidateState();
|
scheduler.InvalidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(blit_color_keys, key);
|
const auto it = std::ranges::find(blit_color_keys, key);
|
||||||
if (it != blit_color_keys.end()) {
|
if (it != blit_color_keys.end()) {
|
||||||
return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
|
return *blit_color_pipelines[std::distance(blit_color_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
blit_color_keys.push_back(key);
|
blit_color_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
|
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
|
const std::array stages = MakeStages(*full_screen_vert, *blit_color_to_color_frag);
|
||||||
const VkPipelineColorBlendAttachmentState blend_attachment{
|
const VkPipelineColorBlendAttachmentState blend_attachment{
|
||||||
@@ -862,7 +1216,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
|
|||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -884,17 +1238,19 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
|
|||||||
return *blit_color_pipelines.back();
|
return *blit_color_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(blit_depth_stencil_keys, key);
|
const auto it = std::ranges::find(blit_depth_stencil_keys, key);
|
||||||
if (it != blit_depth_stencil_keys.end()) {
|
if (it != blit_depth_stencil_keys.end()) {
|
||||||
return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
|
return *blit_depth_stencil_pipelines[std::distance(blit_depth_stencil_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
blit_depth_stencil_keys.push_back(key);
|
blit_depth_stencil_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
|
const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -905,7 +1261,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
|
|||||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
||||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.layout = *two_textures_pipeline_layout,
|
.layout = *two_textures_pipeline_layout,
|
||||||
.renderPass = key.renderpass,
|
.renderPass = key.renderpass,
|
||||||
@@ -916,38 +1272,46 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
|
|||||||
return *blit_depth_stencil_pipelines.back();
|
return *blit_depth_stencil_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key) {
|
VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(clear_color_keys, key);
|
const auto it = std::ranges::find(clear_color_keys, key);
|
||||||
if (it != clear_color_keys.end()) {
|
if (it != clear_color_keys.end()) {
|
||||||
return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
|
return *clear_color_pipelines[std::distance(clear_color_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
clear_color_keys.push_back(key);
|
clear_color_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
|
const std::array stages = MakeStages(*clear_color_vert, *clear_color_frag);
|
||||||
const VkPipelineColorBlendAttachmentState color_blend_attachment_state{
|
const u32 num_color = framebuffer->NumColorAttachments();
|
||||||
.blendEnable = VK_TRUE,
|
constexpr VkColorComponentFlags full_write_mask =
|
||||||
.srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
|
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
|
||||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
|
VK_COLOR_COMPONENT_A_BIT;
|
||||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
std::array<VkPipelineColorBlendAttachmentState, VideoCommon::NUM_RT> blend_attachments{};
|
||||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
|
for (u32 index = 0; index < num_color; ++index) {
|
||||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
|
blend_attachments[index] = VkPipelineColorBlendAttachmentState{
|
||||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
.blendEnable = index == 0 ? VK_TRUE : VK_FALSE,
|
||||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
.srcColorBlendFactor = VK_BLEND_FACTOR_CONSTANT_COLOR,
|
||||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
|
||||||
};
|
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||||
|
.srcAlphaBlendFactor = VK_BLEND_FACTOR_CONSTANT_ALPHA,
|
||||||
|
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
|
||||||
|
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||||
|
.colorWriteMask = index == 0 ? full_write_mask : VkColorComponentFlags{0},
|
||||||
|
};
|
||||||
|
}
|
||||||
const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
|
const VkPipelineColorBlendStateCreateInfo color_blend_state_generic_create_info{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.logicOpEnable = VK_FALSE,
|
.logicOpEnable = VK_FALSE,
|
||||||
.logicOp = VK_LOGIC_OP_CLEAR,
|
.logicOp = VK_LOGIC_OP_CLEAR,
|
||||||
.attachmentCount = 1,
|
.attachmentCount = num_color,
|
||||||
.pAttachments = &color_blend_attachment_state,
|
.pAttachments = blend_attachments.data(),
|
||||||
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||||
};
|
};
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -970,13 +1334,26 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
||||||
const BlitDepthStencilPipelineKey& key) {
|
const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer) {
|
||||||
const auto it = std::ranges::find(clear_stencil_keys, key);
|
const auto it = std::ranges::find(clear_stencil_keys, key);
|
||||||
if (it != clear_stencil_keys.end()) {
|
if (it != clear_stencil_keys.end()) {
|
||||||
return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)];
|
return *clear_stencil_pipelines[std::distance(clear_stencil_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
clear_stencil_keys.push_back(key);
|
clear_stencil_keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
|
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
|
||||||
|
const u32 num_color = framebuffer->NumColorAttachments();
|
||||||
|
std::array<VkPipelineColorBlendAttachmentState, VideoCommon::NUM_RT> blend_attachments{};
|
||||||
|
const VkPipelineColorBlendStateCreateInfo color_blend_ci{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.logicOpEnable = VK_FALSE,
|
||||||
|
.logicOp = VK_LOGIC_OP_CLEAR,
|
||||||
|
.attachmentCount = num_color,
|
||||||
|
.pAttachments = blend_attachments.data(),
|
||||||
|
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||||
|
};
|
||||||
const auto stencil = VkStencilOpState{
|
const auto stencil = VkStencilOpState{
|
||||||
.failOp = VK_STENCIL_OP_KEEP,
|
.failOp = VK_STENCIL_OP_KEEP,
|
||||||
.passOp = VK_STENCIL_OP_REPLACE,
|
.passOp = VK_STENCIL_OP_REPLACE,
|
||||||
@@ -1003,7 +1380,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1014,7 +1391,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pDepthStencilState = &depth_stencil_ci,
|
.pDepthStencilState = &depth_stencil_ci,
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
.pColorBlendState = &color_blend_ci,
|
||||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.layout = *clear_color_pipeline_layout,
|
.layout = *clear_color_pipeline_layout,
|
||||||
.renderPass = key.renderpass,
|
.renderPass = key.renderpass,
|
||||||
@@ -1025,17 +1402,31 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||||||
return *clear_stencil_pipelines.back();
|
return *clear_stencil_pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
VkPipeline BlitImageHelper::FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key,
|
||||||
if (pipeline) {
|
const Framebuffer* framebuffer) {
|
||||||
return;
|
const auto it = std::ranges::find(blit_msaa_color_keys, key);
|
||||||
|
if (it != blit_msaa_color_keys.end()) {
|
||||||
|
return *blit_msaa_color_pipelines[std::distance(blit_msaa_color_keys.begin(), it)];
|
||||||
}
|
}
|
||||||
VkShaderModule frag_shader = *convert_float_to_depth_frag;
|
blit_msaa_color_keys.push_back(key);
|
||||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const std::array stages = MakeStages(*full_screen_vert, *blit_color_msaa_frag);
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
const VkPipelineMultisampleStateCreateInfo multisample_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
|
.rasterizationSamples = key.samples,
|
||||||
|
.sampleShadingEnable = VK_TRUE,
|
||||||
|
.minSampleShading = 1.0f,
|
||||||
|
.pSampleMask = nullptr,
|
||||||
|
.alphaToCoverageEnable = VK_FALSE,
|
||||||
|
.alphaToOneEnable = VK_FALSE,
|
||||||
|
};
|
||||||
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
|
blit_msaa_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
|
.pNext = key.renderpass ? nullptr : &rendering_ci,
|
||||||
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||||
@@ -1043,59 +1434,131 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
|
|||||||
.pTessellationState = nullptr,
|
.pTessellationState = nullptr,
|
||||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &multisample_ci,
|
||||||
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
.pDepthStencilState = nullptr,
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
|
||||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
||||||
.layout = *one_texture_pipeline_layout,
|
|
||||||
.renderPass = renderpass,
|
|
||||||
.subpass = 0,
|
|
||||||
.basePipelineHandle = VK_NULL_HANDLE,
|
|
||||||
.basePipelineIndex = 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass) {
|
|
||||||
if (pipeline) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VkShaderModule frag_shader = *convert_depth_to_float_frag;
|
|
||||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
|
||||||
.pStages = stages.data(),
|
|
||||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
||||||
.pInputAssemblyState = &input_assembly_ci,
|
|
||||||
.pTessellationState = nullptr,
|
|
||||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
||||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
||||||
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
||||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.layout = *one_texture_pipeline_layout,
|
.layout = *one_texture_pipeline_layout,
|
||||||
|
.renderPass = key.renderpass,
|
||||||
|
.subpass = 0,
|
||||||
|
.basePipelineHandle = VK_NULL_HANDLE,
|
||||||
|
.basePipelineIndex = 0,
|
||||||
|
}));
|
||||||
|
return *blit_msaa_color_pipelines.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline BlitImageHelper::FindOrEmplaceResolveDepthStencilPipeline(
|
||||||
|
const Framebuffer* framebuffer, bool resolve_stencil) {
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const ResolveDepthStencilPipelineKey key{
|
||||||
|
.renderpass = renderpass,
|
||||||
|
.depth_format = framebuffer->DepthAttachmentFormat(),
|
||||||
|
};
|
||||||
|
auto& keys = resolve_stencil ? resolve_depth_stencil_keys : resolve_depth_keys;
|
||||||
|
auto& pipelines = resolve_stencil ? resolve_depth_stencil_pipelines : resolve_depth_pipelines;
|
||||||
|
const auto it = std::ranges::find(keys, key);
|
||||||
|
if (it != keys.end()) {
|
||||||
|
return *pipelines[std::distance(keys.begin(), it)];
|
||||||
|
}
|
||||||
|
keys.push_back(key);
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
|
const std::array stages =
|
||||||
|
MakeStages(*full_screen_vert,
|
||||||
|
resolve_stencil ? *blit_depth_stencil_msaa_frag : *blit_depth_msaa_frag);
|
||||||
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
|
pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
|
.pNext = renderpass ? nullptr : &rendering_ci,
|
||||||
|
.flags = 0,
|
||||||
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
|
.pStages = stages.data(),
|
||||||
|
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||||
|
.pInputAssemblyState = &input_assembly_ci,
|
||||||
|
.pTessellationState = nullptr,
|
||||||
|
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||||
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
|
.pDepthStencilState = resolve_stencil ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
|
||||||
|
: &PIPELINE_DEPTH_ONLY_STATE_CREATE_INFO,
|
||||||
|
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
||||||
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
|
.layout = resolve_stencil ? *two_textures_pipeline_layout : *one_texture_pipeline_layout,
|
||||||
.renderPass = renderpass,
|
.renderPass = renderpass,
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
.basePipelineHandle = VK_NULL_HANDLE,
|
.basePipelineHandle = VK_NULL_HANDLE,
|
||||||
.basePipelineIndex = 0,
|
.basePipelineIndex = 0,
|
||||||
});
|
}));
|
||||||
|
return *pipelines.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
VkPipeline BlitImageHelper::FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key) {
|
||||||
|
const auto it = std::ranges::find(msaa_copy_keys, key);
|
||||||
|
if (it != msaa_copy_keys.end()) {
|
||||||
|
return *msaa_copy_pipelines[std::distance(msaa_copy_keys.begin(), it)];
|
||||||
|
}
|
||||||
|
msaa_copy_keys.push_back(key);
|
||||||
|
const std::array stages = MakeStages(*clear_color_vert, key.msaa_to_non_msaa
|
||||||
|
? *convert_msaa_to_non_msaa_frag
|
||||||
|
: *convert_non_msaa_to_msaa_frag);
|
||||||
|
const VkPipelineMultisampleStateCreateInfo multisample_ci{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.rasterizationSamples = key.samples,
|
||||||
|
.sampleShadingEnable = key.msaa_to_non_msaa ? VK_FALSE : VK_TRUE,
|
||||||
|
.minSampleShading = key.msaa_to_non_msaa ? 0.0f : 1.0f,
|
||||||
|
.pSampleMask = nullptr,
|
||||||
|
.alphaToCoverageEnable = VK_FALSE,
|
||||||
|
.alphaToOneEnable = VK_FALSE,
|
||||||
|
};
|
||||||
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
|
msaa_copy_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
|
.pStages = stages.data(),
|
||||||
|
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||||
|
.pInputAssemblyState = &input_assembly_ci,
|
||||||
|
.pTessellationState = nullptr,
|
||||||
|
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||||
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
|
.pMultisampleState = &multisample_ci,
|
||||||
|
.pDepthStencilState = nullptr,
|
||||||
|
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
||||||
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
|
.layout = *msaa_copy_pipeline_layout,
|
||||||
|
.renderPass = key.renderpass,
|
||||||
|
.subpass = 0,
|
||||||
|
.basePipelineHandle = VK_NULL_HANDLE,
|
||||||
|
.basePipelineIndex = 0,
|
||||||
|
}));
|
||||||
|
return *msaa_copy_pipelines.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
|
ConvertPipeline(pipeline, framebuffer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline,
|
||||||
|
const Framebuffer* framebuffer) {
|
||||||
|
ConvertPipeline(pipeline, framebuffer, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module, bool single_texture,
|
vk::ShaderModule& module, bool single_texture,
|
||||||
bool is_target_depth) {
|
bool is_target_depth) {
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
const std::array stages = MakeStages(*full_screen_vert, *module);
|
const std::array stages = MakeStages(*full_screen_vert, *module);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
@@ -1106,7 +1569,8 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
|
|||||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
|
.pDepthStencilState = is_target_depth ? &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO : nullptr,
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
.pColorBlendState = is_target_depth ? &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO
|
||||||
|
: &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
||||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
|
.layout = single_texture ? *one_texture_pipeline_layout : *two_textures_pipeline_layout,
|
||||||
.renderPass = renderpass,
|
.renderPass = renderpass,
|
||||||
@@ -1116,28 +1580,32 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipelineColorTargetEx(vk::Pipeline& pipeline,
|
||||||
|
const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module) {
|
vk::ShaderModule& module) {
|
||||||
ConvertPipelineEx(pipeline, renderpass, module, false, false);
|
ConvertPipelineEx(pipeline, framebuffer, module, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline,
|
||||||
|
const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module) {
|
vk::ShaderModule& module) {
|
||||||
ConvertPipelineEx(pipeline, renderpass, module, true, true);
|
ConvertPipelineEx(pipeline, framebuffer, module, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
bool is_target_depth) {
|
bool is_target_depth) {
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci = MakePipelineRenderingCreateInfo(framebuffer);
|
||||||
VkShaderModule frag_shader =
|
VkShaderModule frag_shader =
|
||||||
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
|
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
|
||||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
||||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = renderpass ? nullptr : &rendering_ci,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stageCount = static_cast<u32>(stages.size()),
|
.stageCount = static_cast<u32>(stages.size()),
|
||||||
.pStages = stages.data(),
|
.pStages = stages.data(),
|
||||||
|
|||||||
@@ -6,8 +6,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#include "video_core/engines/fermi_2d.h"
|
#include "video_core/engines/fermi_2d.h"
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
|
#include "video_core/surface.h"
|
||||||
#include "video_core/texture_cache/types.h"
|
#include "video_core/texture_cache/types.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
@@ -20,6 +24,7 @@ using VideoCommon::Region2D;
|
|||||||
class Device;
|
class Device;
|
||||||
class Framebuffer;
|
class Framebuffer;
|
||||||
class ImageView;
|
class ImageView;
|
||||||
|
class RenderPassCache;
|
||||||
class StateTracker;
|
class StateTracker;
|
||||||
class Scheduler;
|
class Scheduler;
|
||||||
|
|
||||||
@@ -28,6 +33,8 @@ struct BlitImagePipelineKey {
|
|||||||
|
|
||||||
VkRenderPass renderpass;
|
VkRenderPass renderpass;
|
||||||
Tegra::Engines::Fermi2D::Operation operation;
|
Tegra::Engines::Fermi2D::Operation operation;
|
||||||
|
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
|
||||||
|
VkFormat depth_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BlitDepthStencilPipelineKey {
|
struct BlitDepthStencilPipelineKey {
|
||||||
@@ -38,6 +45,32 @@ struct BlitDepthStencilPipelineKey {
|
|||||||
u8 stencil_mask;
|
u8 stencil_mask;
|
||||||
u32 stencil_compare_mask;
|
u32 stencil_compare_mask;
|
||||||
u32 stencil_ref;
|
u32 stencil_ref;
|
||||||
|
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
|
||||||
|
VkFormat depth_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MSAACopyPipelineKey {
|
||||||
|
constexpr auto operator<=>(const MSAACopyPipelineKey&) const noexcept = default;
|
||||||
|
|
||||||
|
VkRenderPass renderpass;
|
||||||
|
VkSampleCountFlagBits samples;
|
||||||
|
bool msaa_to_non_msaa;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BlitMSAAPipelineKey {
|
||||||
|
constexpr auto operator<=>(const BlitMSAAPipelineKey&) const noexcept = default;
|
||||||
|
|
||||||
|
VkRenderPass renderpass;
|
||||||
|
VkSampleCountFlagBits samples;
|
||||||
|
std::array<VkFormat, VideoCommon::NUM_RT> color_formats;
|
||||||
|
VkFormat depth_format;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResolveDepthStencilPipelineKey {
|
||||||
|
constexpr auto operator<=>(const ResolveDepthStencilPipelineKey&) const noexcept = default;
|
||||||
|
|
||||||
|
VkRenderPass renderpass;
|
||||||
|
VkFormat depth_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlitImageHelper {
|
class BlitImageHelper {
|
||||||
@@ -55,6 +88,12 @@ public:
|
|||||||
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
VkImage src_image, VkSampler src_sampler, const Region2D& dst_region,
|
||||||
const Region2D& src_region, const Extent3D& src_size);
|
const Region2D& src_region, const Extent3D& src_size);
|
||||||
|
|
||||||
|
void BlitColorMSAA(const Framebuffer* dst_framebuffer, const ImageView& src_image_view,
|
||||||
|
const Region2D& dst_region, const Region2D& src_region);
|
||||||
|
|
||||||
|
void ResolveDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
|
||||||
|
const Region2D& dst_region, const Region2D& src_region);
|
||||||
|
|
||||||
void BlitDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
|
void BlitDepthStencil(const Framebuffer* dst_framebuffer, ImageView& src_image_view,
|
||||||
const Region2D& dst_region, const Region2D& src_region,
|
const Region2D& dst_region, const Region2D& src_region,
|
||||||
Tegra::Engines::Fermi2D::Filter filter,
|
Tegra::Engines::Fermi2D::Filter filter,
|
||||||
@@ -84,6 +123,12 @@ public:
|
|||||||
void ClearDepthStencil(const Framebuffer* dst_framebuffer, bool depth_clear, f32 clear_depth,
|
void ClearDepthStencil(const Framebuffer* dst_framebuffer, bool depth_clear, f32 clear_depth,
|
||||||
u8 stencil_mask, u32 stencil_ref, u32 stencil_compare_mask,
|
u8 stencil_mask, u32 stencil_ref, u32 stencil_compare_mask,
|
||||||
const Region2D& dst_region);
|
const Region2D& dst_region);
|
||||||
|
|
||||||
|
void CopyMSAA(RenderPassCache& render_pass_cache, VkImage dst_image,
|
||||||
|
VideoCore::Surface::PixelFormat dst_format, VkImage src_image,
|
||||||
|
VideoCore::Surface::PixelFormat src_format, u32 num_samples,
|
||||||
|
std::span<const VideoCommon::ImageCopy> copies, bool msaa_to_non_msaa);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
void Convert(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view);
|
const ImageView& src_image_view);
|
||||||
@@ -91,27 +136,36 @@ private:
|
|||||||
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
void ConvertDepthStencil(VkPipeline pipeline, const Framebuffer* dst_framebuffer,
|
||||||
ImageView& src_image_view);
|
ImageView& src_image_view);
|
||||||
|
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
|
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceDepthStencilPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
|
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key);
|
[[nodiscard]] VkPipeline FindOrEmplaceClearColorPipeline(const BlitImagePipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
[[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline(
|
[[nodiscard]] VkPipeline FindOrEmplaceClearStencilPipeline(
|
||||||
const BlitDepthStencilPipelineKey& key);
|
const BlitDepthStencilPipelineKey& key, const Framebuffer* framebuffer);
|
||||||
|
[[nodiscard]] VkPipeline FindOrEmplaceMSAACopyPipeline(const MSAACopyPipelineKey& key);
|
||||||
|
[[nodiscard]] VkPipeline FindOrEmplaceBlitColorMSAAPipeline(const BlitMSAAPipelineKey& key,
|
||||||
|
const Framebuffer* framebuffer);
|
||||||
|
[[nodiscard]] VkPipeline FindOrEmplaceResolveDepthStencilPipeline(const Framebuffer* framebuffer,
|
||||||
|
bool resolve_stencil);
|
||||||
|
|
||||||
void ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass, bool is_target_depth);
|
void ConvertPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
|
bool is_target_depth);
|
||||||
|
|
||||||
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
|
void ConvertDepthToColorPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer);
|
||||||
|
|
||||||
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRenderPass renderpass);
|
void ConvertColorToDepthPipeline(vk::Pipeline& pipeline, const Framebuffer* framebuffer);
|
||||||
|
|
||||||
void ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void ConvertPipelineEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module, bool single_texture, bool is_target_depth);
|
vk::ShaderModule& module, bool single_texture, bool is_target_depth);
|
||||||
|
|
||||||
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void ConvertPipelineColorTargetEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module);
|
vk::ShaderModule& module);
|
||||||
|
|
||||||
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, VkRenderPass renderpass,
|
void ConvertPipelineDepthTargetEx(vk::Pipeline& pipeline, const Framebuffer* framebuffer,
|
||||||
vk::ShaderModule& module);
|
vk::ShaderModule& module);
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
@@ -125,9 +179,13 @@ private:
|
|||||||
vk::PipelineLayout one_texture_pipeline_layout;
|
vk::PipelineLayout one_texture_pipeline_layout;
|
||||||
vk::PipelineLayout two_textures_pipeline_layout;
|
vk::PipelineLayout two_textures_pipeline_layout;
|
||||||
vk::PipelineLayout clear_color_pipeline_layout;
|
vk::PipelineLayout clear_color_pipeline_layout;
|
||||||
|
vk::PipelineLayout msaa_copy_pipeline_layout;
|
||||||
vk::ShaderModule full_screen_vert;
|
vk::ShaderModule full_screen_vert;
|
||||||
vk::ShaderModule blit_color_to_color_frag;
|
vk::ShaderModule blit_color_to_color_frag;
|
||||||
|
vk::ShaderModule blit_color_msaa_frag;
|
||||||
vk::ShaderModule blit_depth_stencil_frag;
|
vk::ShaderModule blit_depth_stencil_frag;
|
||||||
|
vk::ShaderModule blit_depth_msaa_frag;
|
||||||
|
vk::ShaderModule blit_depth_stencil_msaa_frag;
|
||||||
vk::ShaderModule clear_color_vert;
|
vk::ShaderModule clear_color_vert;
|
||||||
vk::ShaderModule clear_color_frag;
|
vk::ShaderModule clear_color_frag;
|
||||||
vk::ShaderModule clear_stencil_frag;
|
vk::ShaderModule clear_stencil_frag;
|
||||||
@@ -138,6 +196,8 @@ private:
|
|||||||
vk::ShaderModule convert_d32f_to_abgr8_frag;
|
vk::ShaderModule convert_d32f_to_abgr8_frag;
|
||||||
vk::ShaderModule convert_d24s8_to_abgr8_frag;
|
vk::ShaderModule convert_d24s8_to_abgr8_frag;
|
||||||
vk::ShaderModule convert_s8d24_to_abgr8_frag;
|
vk::ShaderModule convert_s8d24_to_abgr8_frag;
|
||||||
|
vk::ShaderModule convert_msaa_to_non_msaa_frag;
|
||||||
|
vk::ShaderModule convert_non_msaa_to_msaa_frag;
|
||||||
vk::Sampler linear_sampler;
|
vk::Sampler linear_sampler;
|
||||||
vk::Sampler nearest_sampler;
|
vk::Sampler nearest_sampler;
|
||||||
|
|
||||||
@@ -149,6 +209,21 @@ private:
|
|||||||
std::vector<vk::Pipeline> clear_color_pipelines;
|
std::vector<vk::Pipeline> clear_color_pipelines;
|
||||||
std::vector<BlitDepthStencilPipelineKey> clear_stencil_keys;
|
std::vector<BlitDepthStencilPipelineKey> clear_stencil_keys;
|
||||||
std::vector<vk::Pipeline> clear_stencil_pipelines;
|
std::vector<vk::Pipeline> clear_stencil_pipelines;
|
||||||
|
std::vector<MSAACopyPipelineKey> msaa_copy_keys;
|
||||||
|
std::vector<vk::Pipeline> msaa_copy_pipelines;
|
||||||
|
std::vector<BlitMSAAPipelineKey> blit_msaa_color_keys;
|
||||||
|
std::vector<vk::Pipeline> blit_msaa_color_pipelines;
|
||||||
|
std::vector<ResolveDepthStencilPipelineKey> resolve_depth_keys;
|
||||||
|
std::vector<vk::Pipeline> resolve_depth_pipelines;
|
||||||
|
std::vector<ResolveDepthStencilPipelineKey> resolve_depth_stencil_keys;
|
||||||
|
std::vector<vk::Pipeline> resolve_depth_stencil_pipelines;
|
||||||
|
struct MSAACopyResources {
|
||||||
|
u64 tick;
|
||||||
|
vk::ImageView src_view;
|
||||||
|
vk::ImageView dst_view;
|
||||||
|
vk::Framebuffer framebuffer;
|
||||||
|
};
|
||||||
|
std::deque<MSAACopyResources> msaa_copy_resources;
|
||||||
vk::Pipeline convert_d32_to_r32_pipeline;
|
vk::Pipeline convert_d32_to_r32_pipeline;
|
||||||
vk::Pipeline convert_r32_to_d32_pipeline;
|
vk::Pipeline convert_r32_to_d32_pipeline;
|
||||||
vk::Pipeline convert_d16_to_r16_pipeline;
|
vk::Pipeline convert_d16_to_r16_pipeline;
|
||||||
|
|||||||
@@ -396,6 +396,18 @@ void BufferCacheRuntime::TickFrame(Common::SlotVector<Buffer>& slot_buffers) noe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 BufferCacheRuntime::CurrentTick() {
|
||||||
|
return scheduler.GetMasterSemaphore().CurrentTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 BufferCacheRuntime::KnownGpuTick() {
|
||||||
|
return scheduler.GetMasterSemaphore().KnownGpuTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferCacheRuntime::Wait(u64 buffer_tick) {
|
||||||
|
scheduler.Wait(buffer_tick);
|
||||||
|
}
|
||||||
|
|
||||||
void BufferCacheRuntime::Finish() {
|
void BufferCacheRuntime::Finish() {
|
||||||
scheduler.Finish();
|
scheduler.Finish();
|
||||||
}
|
}
|
||||||
@@ -564,7 +576,7 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
|
|||||||
if (index >= device.GetMaxVertexInputBindings()) {
|
if (index >= device.GetMaxVertexInputBindings()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.IsExtExtendedDynamicStateSupported() && !vertex_input_dynamic_state_active) {
|
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||||
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
||||||
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
||||||
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
||||||
@@ -604,7 +616,7 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
|
|||||||
if (binding_count == 0) {
|
if (binding_count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.IsExtExtendedDynamicStateSupported() && !vertex_input_dynamic_state_active) {
|
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||||
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data());
|
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ public:
|
|||||||
|
|
||||||
void TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept;
|
void TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept;
|
||||||
|
|
||||||
|
u64 CurrentTick();
|
||||||
|
|
||||||
|
u64 KnownGpuTick();
|
||||||
|
|
||||||
|
void Wait(u64 buffer_tick);
|
||||||
|
|
||||||
void Finish();
|
void Finish();
|
||||||
|
|
||||||
u64 GetDeviceLocalMemory() const;
|
u64 GetDeviceLocalMemory() const;
|
||||||
@@ -131,10 +137,6 @@ public:
|
|||||||
|
|
||||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||||
|
|
||||||
void SetVertexInputDynamicState(bool is_active) {
|
|
||||||
vertex_input_dynamic_state_active = is_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);
|
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);
|
||||||
|
|
||||||
void BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
void BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||||
@@ -197,8 +199,6 @@ private:
|
|||||||
|
|
||||||
bool limit_dynamic_storage_buffers = false;
|
bool limit_dynamic_storage_buffers = false;
|
||||||
u32 max_dynamic_storage_buffers = (std::numeric_limits<u32>::max)();
|
u32 max_dynamic_storage_buffers = (std::numeric_limits<u32>::max)();
|
||||||
|
|
||||||
bool vertex_input_dynamic_state_active = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BufferCacheParams {
|
struct BufferCacheParams {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include "video_core/renderer_vulkan/vk_command_pool.h"
|
#include "video_core/renderer_vulkan/vk_command_pool.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
@@ -14,32 +18,52 @@ constexpr size_t COMMAND_BUFFER_POOL_SIZE = 4;
|
|||||||
struct CommandPool::Pool {
|
struct CommandPool::Pool {
|
||||||
vk::CommandPool handle;
|
vk::CommandPool handle;
|
||||||
vk::CommandBuffers cmdbufs;
|
vk::CommandBuffers cmdbufs;
|
||||||
|
u64 tick;
|
||||||
};
|
};
|
||||||
|
|
||||||
CommandPool::CommandPool(MasterSemaphore& master_semaphore_, const Device& device_)
|
CommandPool::CommandPool(MasterSemaphore& master_semaphore_, const Device& device_)
|
||||||
: ResourcePool(master_semaphore_, COMMAND_BUFFER_POOL_SIZE), device{device_} {}
|
: master_semaphore{master_semaphore_}, device{device_} {}
|
||||||
|
|
||||||
CommandPool::~CommandPool() = default;
|
CommandPool::~CommandPool() = default;
|
||||||
|
|
||||||
void CommandPool::Allocate(size_t begin, size_t end) {
|
void CommandPool::AllocatePool() {
|
||||||
// Command buffers are going to be committed, recorded, executed every single usage cycle.
|
|
||||||
// They are also going to be reset when committed.
|
|
||||||
Pool& pool = pools.emplace_back();
|
Pool& pool = pools.emplace_back();
|
||||||
pool.handle = device.GetLogical().CreateCommandPool({
|
pool.handle = device.GetLogical().CreateCommandPool({
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags =
|
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
||||||
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
||||||
.queueFamilyIndex = device.GetGraphicsFamily(),
|
.queueFamilyIndex = device.GetGraphicsFamily(),
|
||||||
});
|
});
|
||||||
pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE);
|
pool.cmdbufs = pool.handle.Allocate(COMMAND_BUFFER_POOL_SIZE);
|
||||||
|
pool.tick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandPool::AcquirePool() {
|
||||||
|
if (!pools.empty()) {
|
||||||
|
master_semaphore.Refresh();
|
||||||
|
const u64 gpu_tick = master_semaphore.KnownGpuTick();
|
||||||
|
for (size_t i = 0; i < pools.size(); ++i) {
|
||||||
|
const size_t candidate = (current_pool + 1 + i) % pools.size();
|
||||||
|
if (gpu_tick >= pools[candidate].tick) {
|
||||||
|
current_pool = candidate;
|
||||||
|
current_index = 0;
|
||||||
|
pools[current_pool].handle.Reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllocatePool();
|
||||||
|
current_pool = pools.size() - 1;
|
||||||
|
current_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer CommandPool::Commit() {
|
VkCommandBuffer CommandPool::Commit() {
|
||||||
const size_t index = CommitResource();
|
if (pools.empty() || current_index >= COMMAND_BUFFER_POOL_SIZE) {
|
||||||
const auto pool_index = index / COMMAND_BUFFER_POOL_SIZE;
|
AcquirePool();
|
||||||
const auto sub_index = index % COMMAND_BUFFER_POOL_SIZE;
|
}
|
||||||
return pools[pool_index].cmdbufs[sub_index];
|
Pool& pool = pools[current_pool];
|
||||||
|
pool.tick = master_semaphore.CurrentTick();
|
||||||
|
return pool.cmdbufs[current_index++];
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -6,7 +9,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "video_core/renderer_vulkan/vk_resource_pool.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
@@ -14,20 +17,24 @@ namespace Vulkan {
|
|||||||
class Device;
|
class Device;
|
||||||
class MasterSemaphore;
|
class MasterSemaphore;
|
||||||
|
|
||||||
class CommandPool final : public ResourcePool {
|
class CommandPool final {
|
||||||
public:
|
public:
|
||||||
explicit CommandPool(MasterSemaphore& master_semaphore_, const Device& device_);
|
explicit CommandPool(MasterSemaphore& master_semaphore_, const Device& device_);
|
||||||
~CommandPool() override;
|
~CommandPool();
|
||||||
|
|
||||||
void Allocate(size_t begin, size_t end) override;
|
|
||||||
|
|
||||||
VkCommandBuffer Commit();
|
VkCommandBuffer Commit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Pool;
|
struct Pool;
|
||||||
|
|
||||||
|
void AllocatePool();
|
||||||
|
void AcquirePool();
|
||||||
|
|
||||||
|
MasterSemaphore& master_semaphore;
|
||||||
const Device& device;
|
const Device& device;
|
||||||
std::vector<Pool> pools;
|
std::vector<Pool> pools;
|
||||||
|
size_t current_pool = 0;
|
||||||
|
size_t current_index = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
#include "common/div_ceil.h"
|
#include "common/div_ceil.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
#include "video_core/host_shaders/astc_decoder_comp_spv.h"
|
#include "video_core/host_shaders/astc_decoder_comp_spv.h"
|
||||||
#include "video_core/host_shaders/convert_msaa_to_non_msaa_comp_spv.h"
|
|
||||||
#include "video_core/host_shaders/convert_non_msaa_to_msaa_comp_spv.h"
|
|
||||||
#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h"
|
#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h"
|
||||||
#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h"
|
#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h"
|
||||||
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
||||||
@@ -140,33 +138,6 @@ constexpr DescriptorBankInfo ASTC_BANK_INFO{
|
|||||||
.score = 2,
|
.score = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::array<VkDescriptorSetLayoutBinding, ASTC_NUM_BINDINGS> MSAA_DESCRIPTOR_SET_BINDINGS{{
|
|
||||||
{
|
|
||||||
.binding = 0,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
||||||
.pImmutableSamplers = nullptr,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.binding = 1,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
||||||
.pImmutableSamplers = nullptr,
|
|
||||||
},
|
|
||||||
}};
|
|
||||||
|
|
||||||
constexpr DescriptorBankInfo MSAA_BANK_INFO{
|
|
||||||
.uniform_buffers = 0,
|
|
||||||
.storage_buffers = 0,
|
|
||||||
.texture_buffers = 0,
|
|
||||||
.image_buffers = 0,
|
|
||||||
.textures = 0,
|
|
||||||
.images = 2,
|
|
||||||
.score = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr VkDescriptorUpdateTemplateEntry INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{
|
constexpr VkDescriptorUpdateTemplateEntry INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE{
|
||||||
.dstBinding = 0,
|
.dstBinding = 0,
|
||||||
.dstArrayElement = 0,
|
.dstArrayElement = 0,
|
||||||
@@ -185,15 +156,6 @@ constexpr VkDescriptorUpdateTemplateEntry QUERIES_SCAN_DESCRIPTOR_UPDATE_TEMPLAT
|
|||||||
.stride = sizeof(DescriptorUpdateEntry),
|
.stride = sizeof(DescriptorUpdateEntry),
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr VkDescriptorUpdateTemplateEntry MSAA_DESCRIPTOR_UPDATE_TEMPLATE{
|
|
||||||
.dstBinding = 0,
|
|
||||||
.dstArrayElement = 0,
|
|
||||||
.descriptorCount = 2,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
|
||||||
.offset = 0,
|
|
||||||
.stride = sizeof(DescriptorUpdateEntry),
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr std::array<VkDescriptorUpdateTemplateEntry, ASTC_NUM_BINDINGS>
|
constexpr std::array<VkDescriptorUpdateTemplateEntry, ASTC_NUM_BINDINGS>
|
||||||
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY{{
|
ASTC_PASS_DESCRIPTOR_UPDATE_TEMPLATE_ENTRY{{
|
||||||
{
|
{
|
||||||
@@ -910,100 +872,4 @@ void BlockLinearUnswizzle3DPass::UnswizzleChunk(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_,
|
|
||||||
DescriptorPool& descriptor_pool_,
|
|
||||||
StagingBufferPool& staging_buffer_pool_,
|
|
||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
|
||||||
: ComputePass(device_, scheduler_, descriptor_pool_, MSAA_DESCRIPTOR_SET_BINDINGS,
|
|
||||||
MSAA_DESCRIPTOR_UPDATE_TEMPLATE, MSAA_BANK_INFO, {},
|
|
||||||
CONVERT_NON_MSAA_TO_MSAA_COMP_SPV),
|
|
||||||
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
|
||||||
compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {
|
|
||||||
const auto make_msaa_pipeline = [this](size_t i, std::span<const u32> code) {
|
|
||||||
modules[i] = device.GetLogical().CreateShaderModule({
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.codeSize = static_cast<u32>(code.size_bytes()),
|
|
||||||
.pCode = code.data(),
|
|
||||||
});
|
|
||||||
pipelines[i] = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.stage{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
|
||||||
.module = *modules[i],
|
|
||||||
.pName = "main",
|
|
||||||
.pSpecializationInfo = nullptr,
|
|
||||||
},
|
|
||||||
.layout = *layout,
|
|
||||||
.basePipelineHandle = {},
|
|
||||||
.basePipelineIndex = 0,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
make_msaa_pipeline(0, CONVERT_NON_MSAA_TO_MSAA_COMP_SPV);
|
|
||||||
make_msaa_pipeline(1, CONVERT_MSAA_TO_NON_MSAA_COMP_SPV);
|
|
||||||
}
|
|
||||||
|
|
||||||
MSAACopyPass::~MSAACopyPass() = default;
|
|
||||||
|
|
||||||
void MSAACopyPass::CopyImage(Image& dst_image, Image& src_image,
|
|
||||||
std::span<const VideoCommon::ImageCopy> copies,
|
|
||||||
bool msaa_to_non_msaa) {
|
|
||||||
const VkPipeline msaa_pipeline = *pipelines[msaa_to_non_msaa ? 1 : 0];
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
|
||||||
for (const VideoCommon::ImageCopy& copy : copies) {
|
|
||||||
ASSERT(copy.src_subresource.base_layer == 0);
|
|
||||||
ASSERT(copy.src_subresource.num_layers == 1);
|
|
||||||
ASSERT(copy.dst_subresource.base_layer == 0);
|
|
||||||
ASSERT(copy.dst_subresource.num_layers == 1);
|
|
||||||
|
|
||||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
|
||||||
compute_pass_descriptor_queue.AddImage(
|
|
||||||
src_image.StorageImageView(copy.src_subresource.base_level));
|
|
||||||
compute_pass_descriptor_queue.AddImage(
|
|
||||||
dst_image.StorageImageView(copy.dst_subresource.base_level));
|
|
||||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
|
||||||
|
|
||||||
const Common::Vec3<u32> num_dispatches = {
|
|
||||||
Common::DivCeil(copy.extent.width, 8U),
|
|
||||||
Common::DivCeil(copy.extent.height, 8U),
|
|
||||||
copy.extent.depth,
|
|
||||||
};
|
|
||||||
|
|
||||||
scheduler.Record([this, dst = dst_image.Handle(), msaa_pipeline, num_dispatches,
|
|
||||||
descriptor_data](vk::CommandBuffer cmdbuf) {
|
|
||||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
|
||||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, msaa_pipeline);
|
|
||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
|
||||||
cmdbuf.Dispatch(num_dispatches.x, num_dispatches.y, num_dispatches.z);
|
|
||||||
const VkImageMemoryBarrier write_barrier{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = dst,
|
|
||||||
.subresourceRange{
|
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -164,23 +164,4 @@ private:
|
|||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class MSAACopyPass final : public ComputePass {
|
|
||||||
public:
|
|
||||||
explicit MSAACopyPass(const Device& device_, Scheduler& scheduler_,
|
|
||||||
DescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_,
|
|
||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
|
||||||
~MSAACopyPass();
|
|
||||||
|
|
||||||
void CopyImage(Image& dst_image, Image& src_image,
|
|
||||||
std::span<const VideoCommon::ImageCopy> copies, bool msaa_to_non_msaa);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Scheduler& scheduler;
|
|
||||||
StagingBufferPool& staging_buffer_pool;
|
|
||||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
|
||||||
std::array<vk::ShaderModule, 2> modules;
|
|
||||||
std::array<vk::Pipeline, 2> pipelines;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ public:
|
|||||||
void Configure(Tegra::Engines::KeplerCompute& kepler_compute, Tegra::MemoryManager& gpu_memory,
|
void Configure(Tegra::Engines::KeplerCompute& kepler_compute, Tegra::MemoryManager& gpu_memory,
|
||||||
Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache);
|
Scheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache);
|
||||||
|
|
||||||
|
bool IsBound() const noexcept {
|
||||||
|
return static_cast<bool>(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Device& device;
|
const Device& device;
|
||||||
vk::PipelineCache& pipeline_cache;
|
vk::PipelineCache& pipeline_cache;
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ PixelFormat DecodeFormat(u8 encoded_format) {
|
|||||||
return PixelFormatFromRenderTargetFormat(format);
|
return PixelFormatFromRenderTargetFormat(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderPassKey MakeRenderPassKey(const FixedPipelineState& state) {
|
RenderPassKey MakeRenderPassKey(const FixedPipelineState& state, const Device& device) {
|
||||||
RenderPassKey key;
|
RenderPassKey key{};
|
||||||
std::ranges::transform(state.color_formats, key.color_formats.begin(), DecodeFormat);
|
std::ranges::transform(state.color_formats, key.color_formats.begin(), DecodeFormat);
|
||||||
if (state.depth_enabled != 0) {
|
if (state.depth_enabled != 0) {
|
||||||
const auto depth_format{static_cast<Tegra::DepthFormat>(state.depth_format.Value())};
|
const auto depth_format{static_cast<Tegra::DepthFormat>(state.depth_format.Value())};
|
||||||
@@ -134,6 +134,11 @@ RenderPassKey MakeRenderPassKey(const FixedPipelineState& state) {
|
|||||||
key.depth_format = PixelFormat::Invalid;
|
key.depth_format = PixelFormat::Invalid;
|
||||||
}
|
}
|
||||||
key.samples = MaxwellToVK::MsaaMode(state.msaa_mode);
|
key.samples = MaxwellToVK::MsaaMode(state.msaa_mode);
|
||||||
|
const bool has_color = std::ranges::any_of(key.color_formats, [](PixelFormat format) {
|
||||||
|
return format != PixelFormat::Invalid;
|
||||||
|
});
|
||||||
|
key.resolve_color =
|
||||||
|
key.samples != VK_SAMPLE_COUNT_1_BIT && has_color && device.IsTiler();
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,9 +290,23 @@ GraphicsPipeline::GraphicsPipeline(
|
|||||||
descriptor_update_template =
|
descriptor_update_template =
|
||||||
builder.CreateTemplate(set_layout, *pipeline_layout, uses_push_descriptor);
|
builder.CreateTemplate(set_layout, *pipeline_layout, uses_push_descriptor);
|
||||||
|
|
||||||
const VkRenderPass render_pass{render_pass_cache.Get(MakeRenderPassKey(key.state))};
|
VkRenderPass render_pass{};
|
||||||
|
if (!device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
render_pass = render_pass_cache.Get(MakeRenderPassKey(key.state, device));
|
||||||
|
}
|
||||||
Validate();
|
Validate();
|
||||||
MakePipeline(render_pass);
|
try {
|
||||||
|
MakePipeline(render_pass);
|
||||||
|
} catch (const vk::Exception& exception) {
|
||||||
|
LOG_CRITICAL(Render_Vulkan, "Graphics pipeline build failed: {}", exception.what());
|
||||||
|
std::scoped_lock lock{build_mutex};
|
||||||
|
is_built = true;
|
||||||
|
build_condvar.notify_one();
|
||||||
|
if (shader_notify) {
|
||||||
|
shader_notify->MarkShaderComplete();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (pipeline_statistics) {
|
if (pipeline_statistics) {
|
||||||
pipeline_statistics->Collect(device, *pipeline);
|
pipeline_statistics->Collect(device, *pipeline);
|
||||||
}
|
}
|
||||||
@@ -478,7 +497,6 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||||
buffer_cache.runtime.SetVertexInputDynamicState(HasDynamicVertexInput());
|
|
||||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||||
|
|
||||||
guest_descriptor_queue.Acquire(scheduler, num_descriptor_entries);
|
guest_descriptor_queue.Acquire(scheduler, num_descriptor_entries);
|
||||||
@@ -520,6 +538,9 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||||||
texture_cache.UpdateRenderTargets(false);
|
texture_cache.UpdateRenderTargets(false);
|
||||||
texture_cache.CheckFeedbackLoop(std::span<const VideoCommon::ImageViewInOut>{views.data(),
|
texture_cache.CheckFeedbackLoop(std::span<const VideoCommon::ImageViewInOut>{views.data(),
|
||||||
views.size()});
|
views.size()});
|
||||||
|
if (IsBuilt() && !pipeline) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
ConfigureDraw(rescaling, render_area);
|
ConfigureDraw(rescaling, render_area);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -552,6 +573,9 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
|||||||
uses_render_area = render_area.uses_render_area,
|
uses_render_area = render_area.uses_render_area,
|
||||||
render_area_data = render_area.words](vk::CommandBuffer cmdbuf) {
|
render_area_data = render_area.words](vk::CommandBuffer cmdbuf) {
|
||||||
if (bind_pipeline) {
|
if (bind_pipeline) {
|
||||||
|
if (!pipeline) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
|
||||||
}
|
}
|
||||||
cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS,
|
cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS,
|
||||||
@@ -975,9 +999,47 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RenderPassKey renderpass_key{MakeRenderPassKey(key.state, device)};
|
||||||
|
std::array<VkFormat, Maxwell::NumRenderTargets> color_attachment_formats{};
|
||||||
|
for (size_t index = 0; index < renderpass_key.color_formats.size(); ++index) {
|
||||||
|
const PixelFormat pixel_format{renderpass_key.color_formats[index]};
|
||||||
|
if (pixel_format == PixelFormat::Invalid) {
|
||||||
|
color_attachment_formats[index] = VK_FORMAT_UNDEFINED;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
color_attachment_formats[index] =
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true, pixel_format).format;
|
||||||
|
}
|
||||||
|
VkFormat depth_attachment_format{VK_FORMAT_UNDEFINED};
|
||||||
|
VkFormat stencil_attachment_format{VK_FORMAT_UNDEFINED};
|
||||||
|
if (renderpass_key.depth_format != PixelFormat::Invalid) {
|
||||||
|
const VkFormat format{
|
||||||
|
MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, true,
|
||||||
|
renderpass_key.depth_format)
|
||||||
|
.format};
|
||||||
|
const auto surface_type{VideoCore::Surface::GetFormatType(renderpass_key.depth_format)};
|
||||||
|
if (surface_type == VideoCore::Surface::SurfaceType::Depth ||
|
||||||
|
surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
|
||||||
|
depth_attachment_format = format;
|
||||||
|
}
|
||||||
|
if (surface_type == VideoCore::Surface::SurfaceType::Stencil ||
|
||||||
|
surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
|
||||||
|
stencil_attachment_format = format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const VkPipelineRenderingCreateInfo rendering_ci{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = static_cast<u32>(NumAttachments(key.state)),
|
||||||
|
.pColorAttachmentFormats = color_attachment_formats.data(),
|
||||||
|
.depthAttachmentFormat = depth_attachment_format,
|
||||||
|
.stencilAttachmentFormat = stencil_attachment_format,
|
||||||
|
};
|
||||||
|
|
||||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = device.IsKhrDynamicRenderingSupported() ? &rendering_ci : nullptr,
|
||||||
.flags = flags,
|
.flags = flags,
|
||||||
.stageCount = static_cast<u32>(shader_stages.size()),
|
.stageCount = static_cast<u32>(shader_stages.size()),
|
||||||
.pStages = shader_stages.data(),
|
.pStages = shader_stages.data(),
|
||||||
|
|||||||
@@ -305,12 +305,8 @@ size_t GetTotalPipelineWorkers() {
|
|||||||
std::max<size_t>(static_cast<size_t>(std::thread::hardware_concurrency()), 2ULL) - 1ULL;
|
std::max<size_t>(static_cast<size_t>(std::thread::hardware_concurrency()), 2ULL) - 1ULL;
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
const int configured = AndroidSettings::values.pipeline_worker_count.GetValue();
|
const int configured = AndroidSettings::values.pipeline_worker_count.GetValue();
|
||||||
const int clamped = std::clamp(configured, 4, 8);
|
const size_t desired = static_cast<size_t>(std::max(configured, 1));
|
||||||
const size_t desired = static_cast<size_t>(clamped);
|
return std::min<size_t>(max_core_threads, desired);
|
||||||
if (desired == 0) {
|
|
||||||
return 1ULL;
|
|
||||||
}
|
|
||||||
return std::min(max_core_threads, desired);
|
|
||||||
#else
|
#else
|
||||||
return max_core_threads;
|
return max_core_threads;
|
||||||
#endif
|
#endif
|
||||||
@@ -374,9 +370,11 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_int8 = device.IsInt8Supported(),
|
.support_int8 = device.IsInt8Supported(),
|
||||||
.support_uniform_and_storage_buffer_8bit =
|
.support_uniform_and_storage_buffer_8bit =
|
||||||
device.IsUniformAndStorageBuffer8BitAccessSupported(),
|
device.IsUniformAndStorageBuffer8BitAccessSupported(),
|
||||||
|
.support_storage_buffer_8bit = device.IsStorageBuffer8BitAccessSupported(),
|
||||||
.support_int16 = device.IsShaderInt16Supported(),
|
.support_int16 = device.IsShaderInt16Supported(),
|
||||||
.support_uniform_and_storage_buffer_16bit =
|
.support_uniform_and_storage_buffer_16bit =
|
||||||
device.IsUniformAndStorageBuffer16BitAccessSupported(),
|
device.IsUniformAndStorageBuffer16BitAccessSupported(),
|
||||||
|
.support_storage_buffer_16bit = device.IsStorageBuffer16BitAccessSupported(),
|
||||||
.support_int64 = device.IsShaderInt64Supported(),
|
.support_int64 = device.IsShaderInt64Supported(),
|
||||||
.support_vertex_instance_id = false,
|
.support_vertex_instance_id = false,
|
||||||
.support_float_controls = device.IsKhrShaderFloatControlsSupported(),
|
.support_float_controls = device.IsKhrShaderFloatControlsSupported(),
|
||||||
@@ -395,6 +393,10 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_fp64_signed_zero_nan_preserve =
|
.support_fp64_signed_zero_nan_preserve =
|
||||||
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
|
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
|
||||||
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
|
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
|
||||||
|
.support_workgroup_layout_8bit_access =
|
||||||
|
device.IsWorkgroupMemoryExplicitLayout8BitAccessSupported(),
|
||||||
|
.support_workgroup_layout_16bit_access =
|
||||||
|
device.IsWorkgroupMemoryExplicitLayout16BitAccessSupported(),
|
||||||
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
.support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
|
||||||
.supported_subgroup_stages = supported_subgroup_stages,
|
.supported_subgroup_stages = supported_subgroup_stages,
|
||||||
.support_viewport_index_layer_non_geometry =
|
.support_viewport_index_layer_non_geometry =
|
||||||
@@ -404,6 +406,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_demote_to_helper_invocation =
|
.support_demote_to_helper_invocation =
|
||||||
device.IsExtShaderDemoteToHelperInvocationSupported(),
|
device.IsExtShaderDemoteToHelperInvocationSupported(),
|
||||||
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
|
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
|
||||||
|
.support_shared_int64_atomics = device.IsSharedInt64AtomicsSupported(),
|
||||||
.support_derivative_control = true,
|
.support_derivative_control = true,
|
||||||
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
|
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
|
||||||
.support_native_ndc = device.IsExtDepthClipControlSupported(),
|
.support_native_ndc = device.IsExtDepthClipControlSupported(),
|
||||||
@@ -412,6 +415,12 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
.support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
|
.support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
|
||||||
.support_sampled_image_array_nonuniform_indexing =
|
.support_sampled_image_array_nonuniform_indexing =
|
||||||
device.IsSampledImageArrayNonUniformIndexingSupported(),
|
device.IsSampledImageArrayNonUniformIndexingSupported(),
|
||||||
|
.support_storage_image_array_nonuniform_indexing =
|
||||||
|
device.IsStorageImageArrayNonUniformIndexingSupported(),
|
||||||
|
.support_uniform_texel_buffer_array_nonuniform_indexing =
|
||||||
|
device.IsUniformTexelBufferArrayNonUniformIndexingSupported(),
|
||||||
|
.support_storage_texel_buffer_array_nonuniform_indexing =
|
||||||
|
device.IsStorageTexelBufferArrayNonUniformIndexingSupported(),
|
||||||
|
|
||||||
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
||||||
|
|
||||||
|
|||||||
@@ -241,11 +241,13 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
|||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
{
|
||||||
// update engine as channel may be different.
|
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||||
if (!pipeline->Configure(is_indexed))
|
if (!pipeline->Configure(is_indexed)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpdateDynamicStates();
|
UpdateDynamicStates();
|
||||||
|
|
||||||
@@ -410,7 +412,23 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
|||||||
texture_cache.UpdateRenderTargets(true);
|
texture_cache.UpdateRenderTargets(true);
|
||||||
const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
|
const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
|
||||||
const VkExtent2D render_area = framebuffer->RenderArea();
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
scheduler.RequestRenderpass(framebuffer);
|
|
||||||
|
constexpr bool ENABLE_DEFERRED_CLEAR = true;
|
||||||
|
const bool color_full_channels = regs.clear_surface.R && regs.clear_surface.G &&
|
||||||
|
regs.clear_surface.B && regs.clear_surface.A;
|
||||||
|
const bool stencil_partial = use_stencil && framebuffer->HasAspectStencilBit() &&
|
||||||
|
regs.stencil_front_mask != 0xFF && regs.stencil_front_mask != 0;
|
||||||
|
const bool ds_used = use_depth || use_stencil;
|
||||||
|
const bool ds_deferrable =
|
||||||
|
!ds_used || ((!framebuffer->HasAspectDepthBit() || use_depth) &&
|
||||||
|
(!framebuffer->HasAspectStencilBit() || use_stencil) && !stencil_partial);
|
||||||
|
const bool can_defer_clear = ENABLE_DEFERRED_CLEAR && !regs.clear_control.use_scissor &&
|
||||||
|
regs.clear_surface.layer == 0 &&
|
||||||
|
!scheduler.IsRenderPassActive() &&
|
||||||
|
(!use_color || color_full_channels) && ds_deferrable;
|
||||||
|
if (!can_defer_clear) {
|
||||||
|
scheduler.RequestRenderpass(framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
query_cache.NotifySegment(true);
|
query_cache.NotifySegment(true);
|
||||||
query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable);
|
query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable);
|
||||||
@@ -494,15 +512,19 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
|||||||
clear_value.color.int32[i] = s32(f32(s64(int_size - 1) << 1) * (regs.clear_color[i] - 0.5f));
|
clear_value.color.int32[i] = s32(f32(s64(int_size - 1) << 1) * (regs.clear_color[i] - 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regs.clear_surface.R && regs.clear_surface.G && regs.clear_surface.B && regs.clear_surface.A) {
|
if (color_full_channels) {
|
||||||
scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) {
|
if (can_defer_clear) {
|
||||||
const VkClearAttachment attachment{
|
scheduler.DeferColorClear(framebuffer, color_attachment, clear_value);
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
} else {
|
||||||
.colorAttachment = color_attachment,
|
scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) {
|
||||||
.clearValue = clear_value,
|
const VkClearAttachment attachment{
|
||||||
};
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
cmdbuf.ClearAttachments(attachment, clear_rect);
|
.colorAttachment = color_attachment,
|
||||||
});
|
.clearValue = clear_value,
|
||||||
|
};
|
||||||
|
cmdbuf.ClearAttachments(attachment, clear_rect);
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
u8 color_mask = u8(regs.clear_surface.R | regs.clear_surface.G << 1 | regs.clear_surface.B << 2 | regs.clear_surface.A << 3);
|
u8 color_mask = u8(regs.clear_surface.R | regs.clear_surface.G << 1 | regs.clear_surface.B << 2 | regs.clear_surface.A << 3);
|
||||||
Region2D dst_region = {
|
Region2D dst_region = {
|
||||||
@@ -536,6 +558,11 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
|||||||
blit_image.ClearDepthStencil(framebuffer, use_depth, regs.clear_depth,
|
blit_image.ClearDepthStencil(framebuffer, use_depth, regs.clear_depth,
|
||||||
u8(regs.stencil_front_mask), regs.clear_stencil,
|
u8(regs.stencil_front_mask), regs.clear_stencil,
|
||||||
regs.stencil_front_func_mask, dst_region);
|
regs.stencil_front_func_mask, dst_region);
|
||||||
|
} else if (can_defer_clear) {
|
||||||
|
VkClearValue ds_value{};
|
||||||
|
ds_value.depthStencil.depth = regs.clear_depth;
|
||||||
|
ds_value.depthStencil.stencil = regs.clear_stencil;
|
||||||
|
scheduler.DeferDepthStencilClear(framebuffer, ds_value);
|
||||||
} else {
|
} else {
|
||||||
scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil,
|
scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil,
|
||||||
clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) {
|
clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) {
|
||||||
@@ -569,13 +596,20 @@ void RasterizerVulkan::DispatchCompute() {
|
|||||||
const auto [buffer, offset] =
|
const auto [buffer, offset] =
|
||||||
buffer_cache.ObtainBuffer(*indirect_address, 12, sync_info, post_op);
|
buffer_cache.ObtainBuffer(*indirect_address, 12, sync_info, post_op);
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([indirect_buffer = buffer->Handle(),
|
scheduler.Record([pipeline, indirect_buffer = buffer->Handle(),
|
||||||
indirect_offset = offset](vk::CommandBuffer cmdbuf) {
|
indirect_offset = offset](vk::CommandBuffer cmdbuf) {
|
||||||
|
if (!pipeline->IsBound()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
cmdbuf.DispatchIndirect(indirect_buffer, indirect_offset);
|
cmdbuf.DispatchIndirect(indirect_buffer, indirect_offset);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
|
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
|
||||||
|
const std::array<u32, 3> max_dim{device.GetMaxComputeWorkGroupCount()};
|
||||||
|
if (dim[0] > max_dim[0] || dim[1] > max_dim[1] || dim[2] > max_dim[2]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
static constexpr VkMemoryBarrier READ_BARRIER{
|
static constexpr VkMemoryBarrier READ_BARRIER{
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||||
@@ -585,7 +619,12 @@ void RasterizerVulkan::DispatchCompute() {
|
|||||||
};
|
};
|
||||||
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
scheduler.Record([](vk::CommandBuffer cmdbuf) { cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
0, READ_BARRIER); });
|
0, READ_BARRIER); });
|
||||||
scheduler.Record([dim](vk::CommandBuffer cmdbuf) { cmdbuf.Dispatch(dim[0], dim[1], dim[2]); });
|
scheduler.Record([pipeline, dim](vk::CommandBuffer cmdbuf) {
|
||||||
|
if (!pipeline->IsBound()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cmdbuf.Dispatch(dim[0], dim[1], dim[2]);
|
||||||
|
});
|
||||||
|
|
||||||
// Log compute dispatch
|
// Log compute dispatch
|
||||||
if (GPU::Logging::IsActive() &&
|
if (GPU::Logging::IsActive() &&
|
||||||
@@ -636,7 +675,6 @@ void RasterizerVulkan::FlushRegion(DAddr addr, u64 size, VideoCommon::CacheType
|
|||||||
texture_cache.DownloadMemory(addr, size);
|
texture_cache.DownloadMemory(addr, size);
|
||||||
}
|
}
|
||||||
if ((True(which & VideoCommon::CacheType::BufferCache))) {
|
if ((True(which & VideoCommon::CacheType::BufferCache))) {
|
||||||
std::scoped_lock lock{buffer_cache.mutex};
|
|
||||||
buffer_cache.DownloadMemory(addr, size);
|
buffer_cache.DownloadMemory(addr, size);
|
||||||
}
|
}
|
||||||
if ((True(which & VideoCommon::CacheType::QueryCache))) {
|
if ((True(which & VideoCommon::CacheType::QueryCache))) {
|
||||||
@@ -734,12 +772,15 @@ bool RasterizerVulkan::OnCPUWrite(DAddr addr, u64 size) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr bool ENABLE_TEXTURE_CACHE_INVALIDATION_SKIP = true;
|
||||||
|
|
||||||
void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
|
void RasterizerVulkan::OnCacheInvalidation(DAddr addr, u64 size) {
|
||||||
if (addr == 0 || size == 0) {
|
if (addr == 0 || size == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (!ENABLE_TEXTURE_CACHE_INVALIDATION_SKIP ||
|
||||||
|
device_memory.IsRegionTextureCached(addr, size)) {
|
||||||
std::scoped_lock lock{texture_cache.mutex};
|
std::scoped_lock lock{texture_cache.mutex};
|
||||||
texture_cache.WriteMemory(addr, size);
|
texture_cache.WriteMemory(addr, size);
|
||||||
}
|
}
|
||||||
@@ -1309,15 +1350,22 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
|||||||
}
|
}
|
||||||
if (update_references) {
|
if (update_references) {
|
||||||
[&]() {
|
[&]() {
|
||||||
|
bool changed;
|
||||||
if (regs.stencil_two_side_enable) {
|
if (regs.stencil_two_side_enable) {
|
||||||
if (!state_tracker.CheckStencilReferenceFront(regs.stencil_front_ref) &&
|
const bool front_changed =
|
||||||
!state_tracker.CheckStencilReferenceBack(regs.stencil_back_ref)) {
|
state_tracker.CheckStencilReferenceFront(regs.stencil_front_ref);
|
||||||
return;
|
const bool back_changed =
|
||||||
}
|
state_tracker.CheckStencilReferenceBack(regs.stencil_back_ref);
|
||||||
|
changed = front_changed || back_changed;
|
||||||
} else {
|
} else {
|
||||||
if (!state_tracker.CheckStencilReferenceFront(regs.stencil_front_ref)) {
|
const bool front_changed =
|
||||||
return;
|
state_tracker.CheckStencilReferenceFront(regs.stencil_front_ref);
|
||||||
}
|
const bool back_changed =
|
||||||
|
state_tracker.CheckStencilReferenceBack(regs.stencil_front_ref);
|
||||||
|
changed = front_changed || back_changed;
|
||||||
|
}
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
scheduler.Record([front_ref = regs.stencil_front_ref, back_ref = regs.stencil_back_ref,
|
scheduler.Record([front_ref = regs.stencil_front_ref, back_ref = regs.stencil_back_ref,
|
||||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||||
@@ -1334,15 +1382,22 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
|||||||
}
|
}
|
||||||
if (update_write_mask) {
|
if (update_write_mask) {
|
||||||
[&]() {
|
[&]() {
|
||||||
|
bool changed;
|
||||||
if (regs.stencil_two_side_enable) {
|
if (regs.stencil_two_side_enable) {
|
||||||
if (!state_tracker.CheckStencilWriteMaskFront(regs.stencil_front_mask) &&
|
const bool front_changed =
|
||||||
!state_tracker.CheckStencilWriteMaskBack(regs.stencil_back_mask)) {
|
state_tracker.CheckStencilWriteMaskFront(regs.stencil_front_mask);
|
||||||
return;
|
const bool back_changed =
|
||||||
}
|
state_tracker.CheckStencilWriteMaskBack(regs.stencil_back_mask);
|
||||||
|
changed = front_changed || back_changed;
|
||||||
} else {
|
} else {
|
||||||
if (!state_tracker.CheckStencilWriteMaskFront(regs.stencil_front_mask)) {
|
const bool front_changed =
|
||||||
return;
|
state_tracker.CheckStencilWriteMaskFront(regs.stencil_front_mask);
|
||||||
}
|
const bool back_changed =
|
||||||
|
state_tracker.CheckStencilWriteMaskBack(regs.stencil_front_mask);
|
||||||
|
changed = front_changed || back_changed;
|
||||||
|
}
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
scheduler.Record([front_write_mask = regs.stencil_front_mask,
|
scheduler.Record([front_write_mask = regs.stencil_front_mask,
|
||||||
back_write_mask = regs.stencil_back_mask,
|
back_write_mask = regs.stencil_back_mask,
|
||||||
@@ -1360,15 +1415,22 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
|||||||
}
|
}
|
||||||
if (update_compare_masks) {
|
if (update_compare_masks) {
|
||||||
[&]() {
|
[&]() {
|
||||||
|
bool changed;
|
||||||
if (regs.stencil_two_side_enable) {
|
if (regs.stencil_two_side_enable) {
|
||||||
if (!state_tracker.CheckStencilCompareMaskFront(regs.stencil_front_func_mask) &&
|
const bool front_changed =
|
||||||
!state_tracker.CheckStencilCompareMaskBack(regs.stencil_back_func_mask)) {
|
state_tracker.CheckStencilCompareMaskFront(regs.stencil_front_func_mask);
|
||||||
return;
|
const bool back_changed =
|
||||||
}
|
state_tracker.CheckStencilCompareMaskBack(regs.stencil_back_func_mask);
|
||||||
|
changed = front_changed || back_changed;
|
||||||
} else {
|
} else {
|
||||||
if (!state_tracker.CheckStencilCompareMaskFront(regs.stencil_front_func_mask)) {
|
const bool front_changed =
|
||||||
return;
|
state_tracker.CheckStencilCompareMaskFront(regs.stencil_front_func_mask);
|
||||||
}
|
const bool back_changed =
|
||||||
|
state_tracker.CheckStencilCompareMaskBack(regs.stencil_front_func_mask);
|
||||||
|
changed = front_changed || back_changed;
|
||||||
|
}
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
scheduler.Record([front_test_mask = regs.stencil_front_func_mask,
|
scheduler.Record([front_test_mask = regs.stencil_front_func_mask,
|
||||||
back_test_mask = regs.stencil_back_func_mask,
|
back_test_mask = regs.stencil_back_func_mask,
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ using VideoCore::Surface::SurfaceType;
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format,
|
VkAttachmentDescription AttachmentDescription(const Device& device, PixelFormat format,
|
||||||
VkSampleCountFlagBits samples) {
|
VkSampleCountFlagBits samples,
|
||||||
|
VkAttachmentLoadOp load_op,
|
||||||
|
VkAttachmentStoreOp store_op) {
|
||||||
using MaxwellToVK::SurfaceFormat;
|
using MaxwellToVK::SurfaceFormat;
|
||||||
|
|
||||||
const SurfaceType surface_type = GetSurfaceType(format);
|
const SurfaceType surface_type = GetSurfaceType(format);
|
||||||
@@ -55,12 +57,10 @@ using VideoCore::Surface::SurfaceType;
|
|||||||
.flags = {},
|
.flags = {},
|
||||||
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
.format = SurfaceFormat(device, FormatType::Optimal, true, format).format,
|
||||||
.samples = samples,
|
.samples = samples,
|
||||||
.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD,
|
.loadOp = load_op,
|
||||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
.storeOp = store_op,
|
||||||
.stencilLoadOp = has_stencil ? VK_ATTACHMENT_LOAD_OP_LOAD
|
.stencilLoadOp = has_stencil ? load_op : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
: VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
.stencilStoreOp = has_stencil ? store_op : VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
||||||
.stencilStoreOp = has_stencil ? VK_ATTACHMENT_STORE_OP_STORE
|
|
||||||
: VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
||||||
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.initialLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
};
|
};
|
||||||
@@ -87,7 +87,14 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
|||||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
};
|
};
|
||||||
if (is_valid) {
|
if (is_valid) {
|
||||||
descriptions.push_back(AttachmentDescription(*device, format, key.samples));
|
const VkAttachmentLoadOp load_op = (key.color_clear_mask & (1u << index)) != 0
|
||||||
|
? VK_ATTACHMENT_LOAD_OP_CLEAR
|
||||||
|
: VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
const VkAttachmentStoreOp store_op = (key.color_discard_mask & (1u << index)) != 0
|
||||||
|
? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
descriptions.push_back(
|
||||||
|
AttachmentDescription(*device, format, key.samples, load_op, store_op));
|
||||||
num_attachments = static_cast<u32>(index + 1);
|
num_attachments = static_cast<u32>(index + 1);
|
||||||
++num_colors;
|
++num_colors;
|
||||||
}
|
}
|
||||||
@@ -99,7 +106,32 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
|||||||
.attachment = num_colors,
|
.attachment = num_colors,
|
||||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
};
|
};
|
||||||
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples));
|
const VkAttachmentLoadOp depth_load_op = key.depth_stencil_clear
|
||||||
|
? VK_ATTACHMENT_LOAD_OP_CLEAR
|
||||||
|
: VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
descriptions.push_back(AttachmentDescription(*device, key.depth_format, key.samples,
|
||||||
|
depth_load_op, VK_ATTACHMENT_STORE_OP_STORE));
|
||||||
|
}
|
||||||
|
std::array<VkAttachmentReference, 8> resolve_references{};
|
||||||
|
const bool do_resolve_color =
|
||||||
|
key.resolve_color && key.samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0;
|
||||||
|
if (do_resolve_color) {
|
||||||
|
for (size_t index = 0; index < key.color_formats.size(); ++index) {
|
||||||
|
const PixelFormat format{key.color_formats[index]};
|
||||||
|
const bool is_valid{format != PixelFormat::Invalid};
|
||||||
|
resolve_references[index] = VkAttachmentReference{
|
||||||
|
.attachment = is_valid ? static_cast<u32>(descriptions.size()) : VK_ATTACHMENT_UNUSED,
|
||||||
|
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
};
|
||||||
|
if (is_valid) {
|
||||||
|
VkAttachmentDescription resolve_desc =
|
||||||
|
AttachmentDescription(*device, format, VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
||||||
|
VK_ATTACHMENT_STORE_OP_STORE);
|
||||||
|
resolve_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
descriptions.push_back(resolve_desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const VkSubpassDescription subpass{
|
const VkSubpassDescription subpass{
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
@@ -108,7 +140,7 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
|||||||
.pInputAttachments = nullptr,
|
.pInputAttachments = nullptr,
|
||||||
.colorAttachmentCount = num_attachments,
|
.colorAttachmentCount = num_attachments,
|
||||||
.pColorAttachments = references.data(),
|
.pColorAttachments = references.data(),
|
||||||
.pResolveAttachments = nullptr,
|
.pResolveAttachments = do_resolve_color ? resolve_references.data() : nullptr,
|
||||||
.pDepthStencilAttachment = has_depth ? &depth_reference : nullptr,
|
.pDepthStencilAttachment = has_depth ? &depth_reference : nullptr,
|
||||||
.preserveAttachmentCount = 0,
|
.preserveAttachmentCount = 0,
|
||||||
.pPreserveAttachments = nullptr,
|
.pPreserveAttachments = nullptr,
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ struct RenderPassKey {
|
|||||||
std::array<VideoCore::Surface::PixelFormat, 8> color_formats;
|
std::array<VideoCore::Surface::PixelFormat, 8> color_formats;
|
||||||
VideoCore::Surface::PixelFormat depth_format;
|
VideoCore::Surface::PixelFormat depth_format;
|
||||||
VkSampleCountFlagBits samples;
|
VkSampleCountFlagBits samples;
|
||||||
|
bool resolve_color;
|
||||||
|
u32 color_clear_mask;
|
||||||
|
bool depth_stencil_clear;
|
||||||
|
u32 color_discard_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
@@ -30,6 +34,10 @@ struct hash<Vulkan::RenderPassKey> {
|
|||||||
[[nodiscard]] size_t operator()(const Vulkan::RenderPassKey& key) const noexcept {
|
[[nodiscard]] size_t operator()(const Vulkan::RenderPassKey& key) const noexcept {
|
||||||
size_t value = static_cast<size_t>(key.depth_format) << 48;
|
size_t value = static_cast<size_t>(key.depth_format) << 48;
|
||||||
value ^= static_cast<size_t>(key.samples) << 52;
|
value ^= static_cast<size_t>(key.samples) << 52;
|
||||||
|
value ^= static_cast<size_t>(key.resolve_color) << 63;
|
||||||
|
value ^= static_cast<size_t>(key.color_clear_mask) << 54;
|
||||||
|
value ^= static_cast<size_t>(key.depth_stencil_clear) << 62;
|
||||||
|
value ^= static_cast<size_t>(key.color_discard_mask) << 24;
|
||||||
for (size_t i = 0; i < key.color_formats.size(); ++i) {
|
for (size_t i = 0; i < key.color_formats.size(); ++i) {
|
||||||
value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6);
|
value ^= static_cast<size_t>(key.color_formats[i]) << (i * 6);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,6 @@
|
|||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
constexpr u64 MAX_PENDING_FLUSHES = 5;
|
|
||||||
|
|
||||||
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
|
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
|
||||||
vk::CommandBuffer upload_cmdbuf) {
|
vk::CommandBuffer upload_cmdbuf) {
|
||||||
auto command = first;
|
auto command = first;
|
||||||
@@ -49,15 +47,6 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
|
|||||||
master_semaphore{std::make_unique<MasterSemaphore>(device)},
|
master_semaphore{std::make_unique<MasterSemaphore>(device)},
|
||||||
command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} {
|
command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} {
|
||||||
|
|
||||||
/*// PRE-OPTIMIZATION: Warm up the pool to prevent mid-frame spikes
|
|
||||||
{
|
|
||||||
std::scoped_lock rl{reserve_mutex};
|
|
||||||
chunk_reserve.reserve(2048); // Prevent vector resizing
|
|
||||||
for (int i = 0; i < 1024; ++i) {
|
|
||||||
chunk_reserve.push_back(std::make_unique<CommandChunk>());
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
AcquireNewChunk();
|
AcquireNewChunk();
|
||||||
AllocateWorkerCommandBuffer();
|
AllocateWorkerCommandBuffer();
|
||||||
worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); });
|
worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); });
|
||||||
@@ -66,18 +55,7 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
|
|||||||
Scheduler::~Scheduler() = default;
|
Scheduler::~Scheduler() = default;
|
||||||
|
|
||||||
u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
|
u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
|
||||||
// Prevent the CPU from getting too far ahead of the GPU by limiting pending flushes.
|
// When flushing, we only send data to the worker thread; no waiting is necessary.
|
||||||
const bool should_throttle = Settings::IsGPULevelHigh();
|
|
||||||
if (should_throttle) {
|
|
||||||
const u64 current_tick = master_semaphore->CurrentTick();
|
|
||||||
const u64 gap = current_tick > last_submitted_tick ? current_tick - last_submitted_tick : 0;
|
|
||||||
const u64 step = (std::min)(MAX_PENDING_FLUSHES, gap);
|
|
||||||
const u64 new_tick = last_submitted_tick + step;
|
|
||||||
if (new_tick < current_tick) {
|
|
||||||
last_submitted_tick = new_tick;
|
|
||||||
master_semaphore->Wait(last_submitted_tick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
|
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
|
||||||
AllocateNewContext();
|
AllocateNewContext();
|
||||||
return signal_value;
|
return signal_value;
|
||||||
@@ -115,30 +93,67 @@ void Scheduler::DispatchWork() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
|
void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const DeferredClear* clear) {
|
||||||
const VkRenderPass renderpass = framebuffer->RenderPass();
|
|
||||||
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
|
||||||
const VkExtent2D render_area = framebuffer->RenderArea();
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer &&
|
std::array<VkImageView, 9> attachment_views{};
|
||||||
render_area.width == state.render_area.width &&
|
const auto& color_views = framebuffer->ColorAttachments();
|
||||||
render_area.height == state.render_area.height) {
|
for (size_t index = 0; index < color_views.size(); ++index) {
|
||||||
return;
|
attachment_views[index] = color_views[index];
|
||||||
}
|
}
|
||||||
EndRenderPass();
|
attachment_views[8] = framebuffer->DepthAttachment();
|
||||||
state.renderpass = renderpass;
|
state.renderpass = VkRenderPass{};
|
||||||
state.framebuffer = framebuffer_handle;
|
state.framebuffer = VkFramebuffer{};
|
||||||
|
state.attachment_views = attachment_views;
|
||||||
|
state.color_resolve_views = framebuffer->ColorResolveAttachments();
|
||||||
|
state.color_resolve_modes = framebuffer->ColorResolveModes();
|
||||||
|
state.discards_msaa_color = framebuffer->DiscardsMsaaColor();
|
||||||
|
state.discards_msaa_depth = framebuffer->DiscardsMsaaDepth();
|
||||||
state.render_area = render_area;
|
state.render_area = render_area;
|
||||||
|
state.num_color = framebuffer->NumColorAttachments();
|
||||||
|
state.has_depth = framebuffer->HasAspectDepthBit();
|
||||||
|
state.has_stencil = framebuffer->HasAspectStencilBit();
|
||||||
|
state.layer_count = framebuffer->NumLayers();
|
||||||
|
state.rendering = true;
|
||||||
|
|
||||||
// Log render pass begin
|
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||||
if (GPU::Logging::IsActive() &&
|
const std::string render_pass_info =
|
||||||
Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
fmt::format("renderArea={}x{}, numImages={}", render_area.width, render_area.height,
|
||||||
const std::string render_pass_info = fmt::format(
|
framebuffer->NumImages());
|
||||||
"renderArea={}x{}, numImages={}",
|
|
||||||
render_area.width, render_area.height, framebuffer->NumImages());
|
|
||||||
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
|
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Record([renderpass, framebuffer_handle, render_area](vk::CommandBuffer cmdbuf) {
|
RecordDynamicBegin(clear);
|
||||||
|
num_renderpass_images = framebuffer->NumImages();
|
||||||
|
renderpass_images = framebuffer->Images();
|
||||||
|
renderpass_image_ranges = framebuffer->ImageRanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
|
||||||
|
const VkClearValue* clear_values, u32 clear_value_count) {
|
||||||
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
BeginDynamicRendering(framebuffer, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
|
state.renderpass = renderpass;
|
||||||
|
state.framebuffer = framebuffer_handle;
|
||||||
|
state.render_area = render_area;
|
||||||
|
state.rendering = true;
|
||||||
|
|
||||||
|
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||||
|
const std::string render_pass_info =
|
||||||
|
fmt::format("renderArea={}x{}, numImages={}", render_area.width, render_area.height,
|
||||||
|
framebuffer->NumImages());
|
||||||
|
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkClearValue, 9> values{};
|
||||||
|
for (u32 i = 0; i < clear_value_count && i < values.size(); ++i) {
|
||||||
|
values[i] = clear_values[i];
|
||||||
|
}
|
||||||
|
Record([renderpass, framebuffer_handle, render_area, values, clear_value_count](
|
||||||
|
vk::CommandBuffer cmdbuf) {
|
||||||
const VkRenderPassBeginInfo renderpass_bi{
|
const VkRenderPassBeginInfo renderpass_bi{
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
@@ -149,8 +164,8 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
|
|||||||
.offset = {.x = 0, .y = 0},
|
.offset = {.x = 0, .y = 0},
|
||||||
.extent = render_area,
|
.extent = render_area,
|
||||||
},
|
},
|
||||||
.clearValueCount = 0,
|
.clearValueCount = clear_value_count,
|
||||||
.pClearValues = nullptr,
|
.pClearValues = clear_value_count != 0 ? values.data() : nullptr,
|
||||||
};
|
};
|
||||||
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
cmdbuf.BeginRenderPass(renderpass_bi, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
});
|
});
|
||||||
@@ -159,6 +174,102 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
|
|||||||
renderpass_image_ranges = framebuffer->ImageRanges();
|
renderpass_image_ranges = framebuffer->ImageRanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::RealizeDeferredClear() {
|
||||||
|
if (deferred_clear.framebuffer == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const DeferredClear dc = deferred_clear;
|
||||||
|
deferred_clear = {};
|
||||||
|
|
||||||
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
EndRenderPass();
|
||||||
|
BeginDynamicRendering(dc.framebuffer, &dc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkClearValue, 9> clear_values{};
|
||||||
|
u32 count = 0;
|
||||||
|
const RenderPassKey& base = dc.framebuffer->RenderPassKeyBase();
|
||||||
|
for (u32 slot = 0; slot < 8; ++slot) {
|
||||||
|
if (base.color_formats[slot] == VideoCore::Surface::PixelFormat::Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
clear_values[count++] = dc.color_values[slot];
|
||||||
|
}
|
||||||
|
if (base.depth_format != VideoCore::Surface::PixelFormat::Invalid) {
|
||||||
|
clear_values[count++] = dc.depth_stencil_value;
|
||||||
|
}
|
||||||
|
const u32 color_discard_mask =
|
||||||
|
dc.framebuffer->DiscardsMsaaColor() ? dc.color_clear_mask : 0u;
|
||||||
|
const VkRenderPass renderpass = dc.framebuffer->RenderPassVariant(
|
||||||
|
dc.color_clear_mask, dc.depth_stencil, color_discard_mask);
|
||||||
|
EndRenderPass();
|
||||||
|
BeginRenderPassImpl(dc.framebuffer, renderpass, clear_values.data(), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scheduler::DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot,
|
||||||
|
const VkClearValue& value) {
|
||||||
|
if (IsRenderPassActive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (deferred_clear.framebuffer != nullptr && deferred_clear.framebuffer != framebuffer) {
|
||||||
|
RealizeDeferredClear();
|
||||||
|
EndRenderPass();
|
||||||
|
}
|
||||||
|
deferred_clear.framebuffer = framebuffer;
|
||||||
|
deferred_clear.color_clear_mask |= 1u << rt_slot;
|
||||||
|
deferred_clear.color_values[rt_slot] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Scheduler::DeferDepthStencilClear(const Framebuffer* framebuffer, const VkClearValue& value) {
|
||||||
|
if (IsRenderPassActive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (deferred_clear.framebuffer != nullptr && deferred_clear.framebuffer != framebuffer) {
|
||||||
|
RealizeDeferredClear();
|
||||||
|
EndRenderPass();
|
||||||
|
}
|
||||||
|
deferred_clear.framebuffer = framebuffer;
|
||||||
|
deferred_clear.depth_stencil = true;
|
||||||
|
deferred_clear.depth_stencil_value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer) {
|
||||||
|
if (deferred_clear.framebuffer == framebuffer) {
|
||||||
|
RealizeDeferredClear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const VkExtent2D render_area = framebuffer->RenderArea();
|
||||||
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
std::array<VkImageView, 9> attachment_views{};
|
||||||
|
const auto& color_views = framebuffer->ColorAttachments();
|
||||||
|
for (size_t index = 0; index < color_views.size(); ++index) {
|
||||||
|
attachment_views[index] = color_views[index];
|
||||||
|
}
|
||||||
|
attachment_views[8] = framebuffer->DepthAttachment();
|
||||||
|
if (state.rendering && attachment_views == state.attachment_views &&
|
||||||
|
render_area.width == state.render_area.width &&
|
||||||
|
render_area.height == state.render_area.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EndRenderPass();
|
||||||
|
BeginDynamicRendering(framebuffer, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const VkRenderPass renderpass = framebuffer->RenderPass();
|
||||||
|
const VkFramebuffer framebuffer_handle = framebuffer->Handle();
|
||||||
|
if (renderpass == state.renderpass && framebuffer_handle == state.framebuffer &&
|
||||||
|
render_area.width == state.render_area.width &&
|
||||||
|
render_area.height == state.render_area.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Ends any active pass and realizes a deferred clear
|
||||||
|
EndRenderPass();
|
||||||
|
BeginRenderPassImpl(framebuffer, renderpass, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::RequestOutsideRenderPassOperationContext() {
|
void Scheduler::RequestOutsideRenderPassOperationContext() {
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
}
|
}
|
||||||
@@ -323,6 +434,80 @@ void Scheduler::InvalidateState() {
|
|||||||
state_tracker.InvalidateCommandBufferState();
|
state_tracker.InvalidateCommandBufferState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
|
||||||
|
const std::array<VkImageView, 9> views = state.attachment_views;
|
||||||
|
const std::array<VkImageView, 8> resolve_views = state.color_resolve_views;
|
||||||
|
const std::array<VkResolveModeFlagBits, 8> resolve_modes = state.color_resolve_modes;
|
||||||
|
const u32 num_color = state.num_color;
|
||||||
|
const bool has_depth = state.has_depth;
|
||||||
|
const bool has_stencil = state.has_stencil;
|
||||||
|
const u32 layers = state.layer_count;
|
||||||
|
const VkExtent2D render_area = state.render_area;
|
||||||
|
const u32 color_clear_mask = clear ? clear->color_clear_mask : 0u;
|
||||||
|
const u32 color_discard_mask =
|
||||||
|
clear != nullptr && state.discards_msaa_color ? clear->color_clear_mask : 0u;
|
||||||
|
const std::array<VkClearValue, 8> color_clear_values =
|
||||||
|
clear ? clear->color_values : std::array<VkClearValue, 8>{};
|
||||||
|
const bool ds_clear = clear != nullptr && clear->depth_stencil;
|
||||||
|
const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{};
|
||||||
|
const bool ds_discard = state.discards_msaa_depth;
|
||||||
|
Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers,
|
||||||
|
render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear,
|
||||||
|
ds_clear_value, ds_discard](vk::CommandBuffer cmdbuf) {
|
||||||
|
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
|
||||||
|
for (u32 index = 0; index < num_color; ++index) {
|
||||||
|
const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0;
|
||||||
|
const VkImageView resolve_view = resolve_views[index];
|
||||||
|
const bool has_resolve = resolve_view != VK_NULL_HANDLE;
|
||||||
|
const bool discard_slot = has_resolve && ((color_discard_mask >> index) & 1u) != 0;
|
||||||
|
color_infos[index] = VkRenderingAttachmentInfo{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = views[index],
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = has_resolve ? resolve_modes[index] : VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = resolve_view,
|
||||||
|
.resolveImageLayout =
|
||||||
|
has_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = clear_slot ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = discard_slot ? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.clearValue = clear_slot ? color_clear_values[index] : VkClearValue{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const VkRenderingAttachmentInfo depth_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = views[8],
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = VK_NULL_HANDLE,
|
||||||
|
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
|
||||||
|
.storeOp = ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_STORE_OP_STORE,
|
||||||
|
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
|
||||||
|
};
|
||||||
|
const VkRenderingInfo rendering_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.renderArea =
|
||||||
|
{
|
||||||
|
.offset = {.x = 0, .y = 0},
|
||||||
|
.extent = render_area,
|
||||||
|
},
|
||||||
|
.layerCount = layers,
|
||||||
|
.viewMask = 0,
|
||||||
|
.colorAttachmentCount = num_color,
|
||||||
|
.pColorAttachments = color_infos.data(),
|
||||||
|
.pDepthAttachment = has_depth ? &depth_info : nullptr,
|
||||||
|
.pStencilAttachment = has_stencil ? &depth_info : nullptr,
|
||||||
|
};
|
||||||
|
cmdbuf.BeginRendering(rendering_info);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::EndPendingOperations() {
|
void Scheduler::EndPendingOperations() {
|
||||||
query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64);
|
query_cache->CounterReset(VideoCommon::QueryType::ZPassPixelCount64);
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
@@ -330,7 +515,8 @@ void Scheduler::EndPendingOperations() {
|
|||||||
|
|
||||||
void Scheduler::EndRenderPass()
|
void Scheduler::EndRenderPass()
|
||||||
{
|
{
|
||||||
if (!state.renderpass) {
|
RealizeDeferredClear();
|
||||||
|
if (!state.rendering) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +534,8 @@ void Scheduler::EndRenderPass()
|
|||||||
Record([num_images = num_renderpass_images,
|
Record([num_images = num_renderpass_images,
|
||||||
images = renderpass_images,
|
images = renderpass_images,
|
||||||
ranges = renderpass_image_ranges,
|
ranges = renderpass_image_ranges,
|
||||||
has_transform_feedback = device.IsExtTransformFeedbackSupported()](
|
has_transform_feedback = device.IsExtTransformFeedbackSupported(),
|
||||||
|
dynamic_rendering = device.IsKhrDynamicRenderingSupported()](
|
||||||
vk::CommandBuffer cmdbuf) {
|
vk::CommandBuffer cmdbuf) {
|
||||||
std::array<VkImageMemoryBarrier, 9> barriers;
|
std::array<VkImageMemoryBarrier, 9> barriers;
|
||||||
for (size_t i = 0; i < num_images; ++i) {
|
for (size_t i = 0; i < num_images; ++i) {
|
||||||
@@ -385,7 +572,11 @@ void Scheduler::EndRenderPass()
|
|||||||
.subresourceRange = range,
|
.subresourceRange = range,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
cmdbuf.EndRenderPass();
|
if (dynamic_rendering) {
|
||||||
|
cmdbuf.EndRendering();
|
||||||
|
} else {
|
||||||
|
cmdbuf.EndRenderPass();
|
||||||
|
}
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE,
|
||||||
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
0, nullptr, nullptr, vk::Span(barriers.data(), num_images));
|
||||||
@@ -403,6 +594,9 @@ void Scheduler::EndRenderPass()
|
|||||||
});
|
});
|
||||||
|
|
||||||
state.renderpass = VkRenderPass{};
|
state.renderpass = VkRenderPass{};
|
||||||
|
state.framebuffer = VkFramebuffer{};
|
||||||
|
state.attachment_views = {};
|
||||||
|
state.rendering = false;
|
||||||
num_renderpass_images = 0;
|
num_renderpass_images = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user