diff --git a/proton-cachyos/.SRCINFO b/proton-cachyos/.SRCINFO index d4b77910..860dc370 100644 --- a/proton-cachyos/.SRCINFO +++ b/proton-cachyos/.SRCINFO @@ -86,8 +86,8 @@ pkgbase = proton-cachyos makedepends = lib32-libxkbcommon makedepends = libvpx makedepends = lib32-libvpx - makedepends = sdl2>=2.0.16 - makedepends = lib32-sdl2>=2.0.16 + makedepends = sdl2 + makedepends = lib32-sdl2 makedepends = libsoup makedepends = lib32-libsoup makedepends = libgudev @@ -126,8 +126,8 @@ pkgbase = proton-cachyos depends = lib32-libxkbcommon depends = libvpx depends = lib32-libvpx - depends = sdl2>=2.0.16 - depends = lib32-sdl2>=2.0.16 + depends = sdl2 + depends = lib32-sdl2 depends = libsoup depends = lib32-libsoup depends = libgudev @@ -175,7 +175,7 @@ pkgbase = proton-cachyos options = !lto options = !debug options = emptydirs - source = proton::git+https://github.com/ValveSoftware/Proton.git#tag=experimental-8.0-20231219 + source = proton::git+https://github.com/ValveSoftware/Proton.git#tag=experimental-bleeding-edge-8.0-80590-20240215-p002645-w191c4e-d9491b5-ve64116 source = https://dl.winehq.org/wine/wine-gecko/2.47.4/wine-gecko-2.47.4-x86.tar.xz source = https://dl.winehq.org/wine/wine-gecko/2.47.4/wine-gecko-2.47.4-x86_64.tar.xz source = https://github.com/madewokherd/wine-mono/releases/download/wine-mono-8.1.0/wine-mono-8.1.0-x86.tar.xz @@ -199,19 +199,19 @@ pkgbase = proton-cachyos sha256sums = 2cfc8d5c948602e21eff8a78613e1826f2d033df9672cace87fed56e8310afb6 sha256sums = fd88fc7e537d058d7a8abf0c1ebc90c574892a466de86706a26d254710a82814 sha256sums = 4e3e8a40729e4c9e3e9e651cebe4f1aed8f9a4d22e991e6cd24608687f0eedd4 - sha256sums = 9dffdab7d53dc81ab82ba86d1f4baa8f85b1fe0410ece76b89295b09aab7fbe0 - sha256sums = f16e8271169cbaca1111e925a02bd0d1dfcfd6a0941435b724734b626689f6c6 + sha256sums = facdd6c59e93f5f0877ba1e68a1f5f90f8cd8333e6fba863760ddfa49330753c + sha256sums = 0ad87e3ca616120ec490361df41e24b445a62ad4f9652b048d156c4859f4a2f6 sha256sums = 369193510b9309fc9cb80fc204220599583677a59976c7f434c2a33871b0cbe1 - sha256sums = 42c869c47a3079087125efa94d786c5942cbd518a7ab087770a5c19d2007e0d6 - sha256sums = 0892daec01d88ae497d1389673931f5aa1a93de56b24eeee6a6beaefcee8943c - sha256sums = c589f9bf60c27033680036a048374632001eddf8a9ca2277c7ed5893263c2ac9 - sha256sums = eefb327133ee164db6d8002a851b8fad72f9fc2e669f1d58901ebdadbc240823 + sha256sums = e76d56f97a795f143ecd718229b9af8a5e2a4d1daffa6e35a26bc68c1c22f68e + sha256sums = a5429443e20a2b5d5f1e90626741b264bac036556202f99c691637815785c989 + sha256sums = 73fabb8d30e174e57ac864a5ec7a3bc6bcd0fd917db4094d3b9ad807ca69a411 + sha256sums = db9f7cca780b4e4225e1cc75501cd348878112936cdc5c832caa8e4dd6614e1a sha256sums = d84f6530acd6d6480fa15cc566665ca2a5af98dbe1b66b4a9295bd186a685585 sha256sums = 2f30e393b5e6c371a68ad6b5b6693d35412d30ba7e3963bc65a650c9c29ff569 - sha256sums = 6464b6a08aa8b117e7395e3a0dcf8d7434936962e790505143446557a7f1d2da + sha256sums = ceff1ff8de8bc25729cc7928eb46d16ef4c2f49ef3eb2e47ce3134337ca7107e sha256sums = ac757218883c65f563e5a211dfbc1be477b9f39e0bba5cd89ae2c867619e5ce3 sha256sums = 80322501d28cc3f288fe206e4e943b5b8a579993f15227ad4f7ce5d879af0d54 - sha256sums = cda9aee7a4cb76a4c85705ccc9c06df0c0e982080111eb884246abfa97d1253a + sha256sums = 21b854b0a78a142c182faabeaed140abeaee88d754fe5ce84a63433a71fd67ed sha256sums = 08af47c4597b9cb5e7984eb7e273d03ba7c205eb4a72f4f91329e5e1d60e90a7 sha256sums = 23e35740995ada449865b0b5129e8177e995d28842a924be4562e65d6513bafd sha256sums = bd0482c05474068bb50a176eb33c02a1eb3ac1bece0365ee0dd3bcd304fabf9e diff --git a/proton-cachyos/0001-AUR-Pkgbuild-changes.patch b/proton-cachyos/0001-AUR-Pkgbuild-changes.patch index bc3245f8..92d26d7b 100644 --- a/proton-cachyos/0001-AUR-Pkgbuild-changes.patch +++ b/proton-cachyos/0001-AUR-Pkgbuild-changes.patch @@ -1,26 +1,26 @@ -From 51d4010480d581842ac324415f24b4b8a6a657d2 Mon Sep 17 00:00:00 2001 +From 3056186c67e1708550d8321843650a106a88d776 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Wed, 26 Apr 2023 14:22:23 +0300 Subject: [PATCH 1/6] AUR Pkgbuild changes --- - Makefile.in | 74 ++++++++++++++++++++++++++-------- + Makefile.in | 75 ++++++++++++++++++++++++++-------- compatibilitytool.vdf.template | 2 +- configure.sh | 2 + make/rules-autoconf.mk | 4 +- make/rules-cargo.mk | 4 +- make/rules-cmake.mk | 4 +- - make/rules-common.mk | 18 +++++---- + make/rules-common.mk | 18 ++++---- make/rules-configure.mk | 4 +- make/rules-makedep.mk | 4 +- make/rules-meson.mk | 3 +- make/rules-winemaker.mk | 2 +- proton | 6 +-- toolmanifest_runtime.vdf | 3 -- - 13 files changed, 88 insertions(+), 42 deletions(-) + 13 files changed, 89 insertions(+), 42 deletions(-) diff --git a/Makefile.in b/Makefile.in -index 7ec939df..32211119 100644 +index 7ec939df..3636f22c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -50,11 +50,12 @@ else @@ -164,7 +164,12 @@ index 7ec939df..32211119 100644 --disable-tests WINE_CONFIGURE_ARGS32 = \ -@@ -527,6 +564,9 @@ DXVK_MESON_ARGS32 = --bindir=$(DXVK_DST32)/lib/wine/dxvk +@@ -523,10 +560,14 @@ $(eval $(call rules-makedep,vrclient,64)) + ## dxvk + ## + ++DXVK_MESON_ARGS = --force-fallback-for=libdisplay-info + DXVK_MESON_ARGS32 = --bindir=$(DXVK_DST32)/lib/wine/dxvk DXVK_MESON_ARGS64 = --bindir=$(DXVK_DST64)/lib64/wine/dxvk DXVK_DEPENDS = glslang @@ -174,7 +179,7 @@ index 7ec939df..32211119 100644 $(eval $(call rules-source,dxvk,$(SRCDIR)/dxvk)) $(eval $(call rules-meson,dxvk,32,CROSS)) $(eval $(call rules-meson,dxvk,64,CROSS)) -@@ -554,6 +594,9 @@ $(OBJ)/.dxvk-post-build32: +@@ -554,6 +595,9 @@ $(OBJ)/.dxvk-post-build32: DXVK_NVAPI_MESON_ARGS32 = --bindir=$(DXVK_NVAPI_DST32)/lib/wine/nvapi DXVK_NVAPI_MESON_ARGS64 = --bindir=$(DXVK_NVAPI_DST64)/lib64/wine/nvapi @@ -184,7 +189,7 @@ index 7ec939df..32211119 100644 $(eval $(call rules-source,dxvk-nvapi,$(SRCDIR)/dxvk-nvapi)) $(eval $(call rules-meson,dxvk-nvapi,32,CROSS)) $(eval $(call rules-meson,dxvk-nvapi,64,CROSS)) -@@ -628,6 +671,9 @@ ifneq ($(UNSTRIPPED_BUILD),) +@@ -628,6 +672,9 @@ ifneq ($(UNSTRIPPED_BUILD),) VKD3D_PROTON_MESON_ARGS = -Denable_trace=true endif @@ -194,7 +199,7 @@ index 7ec939df..32211119 100644 $(eval $(call rules-source,vkd3d-proton,$(SRCDIR)/vkd3d-proton)) $(eval $(call rules-meson,vkd3d-proton,32,CROSS)) $(eval $(call rules-meson,vkd3d-proton,64,CROSS)) -@@ -924,14 +970,14 @@ $(FONTS_OBJ)/source-han/%.ttf: $$(%.ttf_CIDFONT) $$(%.ttf_FEATURES) $$(%.ttf_SEQ +@@ -924,14 +971,14 @@ $(FONTS_OBJ)/source-han/%.ttf: $$(%.ttf_CIDFONT) $$(%.ttf_FEATURES) $$(%.ttf_SEQ mkdir -p $(FONTS_OBJ)/source-han # Do not immediately create the target file, so that make is interrupted # it will restart again @@ -212,7 +217,7 @@ index 7ec939df..32211119 100644 mv $@.tmp $@ $(FONTS_OBJ)/ume-gothic/%.ttf: $$(%.ttf_FONT) $$(%.ttf_NAMETABLE_PATCH) -@@ -941,12 +987,12 @@ $(FONTS_OBJ)/ume-gothic/%.ttf: $$(%.ttf_FONT) $$(%.ttf_NAMETABLE_PATCH) +@@ -941,12 +988,12 @@ $(FONTS_OBJ)/ume-gothic/%.ttf: $$(%.ttf_FONT) $$(%.ttf_NAMETABLE_PATCH) ttx -o $@ -m $($(notdir $@)_FONT) $(FONTS_OBJ)/ume-gothic/$(notdir $(basename $($(notdir $@)_NAMETABLE_PATCH))).ttx $(simsun.ttc): $(simsun.ttf) $(nsimsun.ttf) @@ -228,7 +233,7 @@ index 7ec939df..32211119 100644 $(micross.ttf): $(FONTS)/scripts/merge.py $(noto_sans.ttf) $(noto_sans_arabic.ttf) $(noto_sans_armenian.ttf) $(noto_sans_bengali.ttf) $(noto_sans_coptic.ttf) \ $(noto_sans_georgian.ttf) $(noto_sans_gujarati.ttf) $(noto_sans_hebrew.ttf) $(noto_sans_khmer.ttf) $(noto_sans_tamil.ttf) \ -@@ -1072,8 +1118,8 @@ all-dist: $(DIST_OVR32) $(DIST_OVR64) +@@ -1072,8 +1119,8 @@ all-dist: $(DIST_OVR32) $(DIST_OVR64) ## default_pfx: wine gst_good gst_libav gst_plugins_rs lsteamclient steamexe vrclient wineopenxr dxvk dxvk-nvapi vkd3d-proton @@ -239,7 +244,7 @@ index 7ec939df..32211119 100644 rm -rf $(abspath $(DIST_PREFIX)) python3 $(SRCDIR)/default_pfx.py $(abspath $(DIST_PREFIX)) $(abspath $(DST_DIR)) -@@ -1205,7 +1251,6 @@ ifeq ($(ENABLE_CCACHE),1) +@@ -1205,7 +1252,6 @@ ifeq ($(ENABLE_CCACHE),1) export CCACHE_DIR := $(if $(CCACHE_DIR),$(CCACHE_DIR),$(HOME)/.ccache) override DOCKER_OPTS := -v $(CCACHE_DIR):$(CCACHE_DIR)$(CONTAINER_MOUNT_OPTS) $(CCACHE_ENV) -e CCACHE_DIR=$(CCACHE_DIR) $(DOCKER_OPTS) else @@ -247,7 +252,7 @@ index 7ec939df..32211119 100644 override DOCKER_OPTS := $(CCACHE_ENV) -e CCACHE_DISABLE=1 $(DOCKER_OPTS) endif -@@ -1220,9 +1265,6 @@ ifeq ($(CONTAINER_ENGINE),) +@@ -1220,9 +1266,6 @@ ifeq ($(CONTAINER_ENGINE),) CONTAINER_ENGINE := docker endif @@ -459,7 +464,7 @@ index 5c3b59a3..ed6589e0 100644 winebuild --$(lastword $(subst ., ,$(4))) --fake-module -E "$(basename $(4)).spec" -o "$(4).fake" mkdir -p $$($(2)_LIBDIR$(3))/$(LIBDIR_WINE_$(3)) diff --git a/proton b/proton -index f93f545f..e4713eec 100755 +index 2faa16b6..87b13577 100755 --- a/proton +++ b/proton @@ -423,7 +423,6 @@ class Proton: @@ -470,7 +475,7 @@ index f93f545f..e4713eec 100755 def path(self, d): return self.base_dir + d -@@ -1742,8 +1741,6 @@ if __name__ == "__main__": +@@ -1752,8 +1751,6 @@ if __name__ == "__main__": g_proton = Proton(os.path.dirname(sys.argv[0])) @@ -479,7 +484,7 @@ index f93f545f..e4713eec 100755 g_compatdata = CompatData(os.environ["STEAM_COMPAT_DATA_PATH"]) -@@ -1752,7 +1749,8 @@ if __name__ == "__main__": +@@ -1762,7 +1759,8 @@ if __name__ == "__main__": g_session.init_wine() if g_proton.missing_default_prefix(): @@ -502,5 +507,5 @@ index beddcbbb..b6f36788 100644 - "compatmanager_layer_name" "proton" } -- -2.43.0 +2.43.1 diff --git a/proton-cachyos/0002-AUR-Do-not-update-cargo-crates.patch b/proton-cachyos/0002-AUR-Do-not-update-cargo-crates.patch index 1cea2d77..160e0134 100644 --- a/proton-cachyos/0002-AUR-Do-not-update-cargo-crates.patch +++ b/proton-cachyos/0002-AUR-Do-not-update-cargo-crates.patch @@ -1,4 +1,4 @@ -From 81224ebacaefd19d894afbcde000bda0745ec32b Mon Sep 17 00:00:00 2001 +From 8f433c2161a800e24dcc7c5dd9adb48dad2d6745 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Sun, 19 Mar 2023 10:56:59 +0200 Subject: [PATCH 2/6] AUR Do not update cargo crates @@ -21,5 +21,5 @@ index 00fa99fc..225ab528 100644 -j$$(SUBJOBS) --locked --offline --verbose \ --target "$$(CARGO_TARGET_$(3))" \ -- -2.43.0 +2.43.1 diff --git a/proton-cachyos/0003-AUR-Remove-kaldi-openfst-vosk-api-modules-because-of.patch b/proton-cachyos/0003-AUR-Remove-kaldi-openfst-vosk-api-modules-because-of.patch index bf507d96..cf0eb677 100644 --- a/proton-cachyos/0003-AUR-Remove-kaldi-openfst-vosk-api-modules-because-of.patch +++ b/proton-cachyos/0003-AUR-Remove-kaldi-openfst-vosk-api-modules-because-of.patch @@ -1,4 +1,4 @@ -From 4141a175920b6bb81d589141a04185b9a25509a8 Mon Sep 17 00:00:00 2001 +From 9c69ddbb3082515a94761f1aef10542d4a92c3ac Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Wed, 12 Jul 2023 17:53:47 +0300 Subject: [PATCH 3/6] AUR Remove kaldi, openfst, vosk-api modules because of @@ -9,7 +9,7 @@ Subject: [PATCH 3/6] AUR Remove kaldi, openfst, vosk-api modules because of 1 file changed, 1 insertion(+), 81 deletions(-) diff --git a/Makefile.in b/Makefile.in -index 32211119..1f196b49 100644 +index 3636f22c..ea505e39 100644 --- a/Makefile.in +++ b/Makefile.in @@ -403,86 +403,6 @@ $(OBJ)/.steamexe-post-build64: @@ -109,5 +109,5 @@ index 32211119..1f196b49 100644 $(eval $(call rules-source,wine,$(SRCDIR)/wine)) $(eval $(call rules-autoconf,wine,32)) -- -2.43.0 +2.43.1 diff --git a/proton-cachyos/0004-AUR-Copy-DLL-dependencies-of-32bit-libvkd3d-dlls-int.patch b/proton-cachyos/0004-AUR-Copy-DLL-dependencies-of-32bit-libvkd3d-dlls-int.patch index 84dbfd24..8a0a1885 100644 --- a/proton-cachyos/0004-AUR-Copy-DLL-dependencies-of-32bit-libvkd3d-dlls-int.patch +++ b/proton-cachyos/0004-AUR-Copy-DLL-dependencies-of-32bit-libvkd3d-dlls-int.patch @@ -1,4 +1,4 @@ -From 98c97d55154566292875f73c05e0062a95dee02b Mon Sep 17 00:00:00 2001 +From 70c31f5f82163bbf18cb8338e14f80b9de78b620 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Wed, 12 Jul 2023 03:16:34 +0300 Subject: [PATCH 4/6] AUR Copy DLL dependencies of 32bit libvkd3d dlls into the @@ -20,10 +20,10 @@ a runtime dependency. 1 file changed, 9 insertions(+) diff --git a/proton b/proton -index e4713eec..b489aa96 100755 +index 87b13577..8d13f941 100755 --- a/proton +++ b/proton -@@ -918,6 +918,15 @@ class CompatData: +@@ -921,6 +921,15 @@ class CompatData: prefix=self.prefix_dir, track_file=tracked_files, link_debug=True) try_copy(g_proton.lib_dir + "vkd3d/libvkd3d-shader-1.dll", "drive_c/windows/syswow64", prefix=self.prefix_dir, track_file=tracked_files, link_debug=True) @@ -40,5 +40,5 @@ index e4713eec..b489aa96 100755 if use_wined3d: dxvkfiles = [] -- -2.43.0 +2.43.1 diff --git a/proton-cachyos/0005-AUR-Strip-binaries-early.patch b/proton-cachyos/0005-AUR-Strip-binaries-early.patch index 93045821..65f9b964 100644 --- a/proton-cachyos/0005-AUR-Strip-binaries-early.patch +++ b/proton-cachyos/0005-AUR-Strip-binaries-early.patch @@ -1,4 +1,4 @@ -From 230c3144ea0894e9b0e692cef5b913801b967ff7 Mon Sep 17 00:00:00 2001 +From c8de8d2e84662b3eca41111d84a3d74bc363a955 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Wed, 23 Aug 2023 19:31:35 +0300 Subject: [PATCH 5/6] AUR Strip binaries early @@ -8,7 +8,7 @@ Subject: [PATCH 5/6] AUR Strip binaries early 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in -index 1f196b49..b70e1e48 100644 +index ea505e39..892d78b1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -54,7 +54,7 @@ CFLAGS ?= -O2 -march=nocona -mtune=core-avx2 @@ -21,5 +21,5 @@ index 1f196b49..b70e1e48 100644 COMMON_FLAGS64 := -mcmodel=small CARGO_BUILD_ARGS += --release -- -2.43.0 +2.43.1 diff --git a/proton-cachyos/0006-AUR-Fix-hwnd-redefinition.patch b/proton-cachyos/0006-AUR-Fix-hwnd-redefinition.patch index 11a08f5c..5579d9f8 100644 --- a/proton-cachyos/0006-AUR-Fix-hwnd-redefinition.patch +++ b/proton-cachyos/0006-AUR-Fix-hwnd-redefinition.patch @@ -1,4 +1,4 @@ -From d898a375310be217a70b818b772ccdd375716b85 Mon Sep 17 00:00:00 2001 +From 9def0147d49fc860d0ba590bd1e7f90fe8a8e410 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Thu, 28 Sep 2023 14:16:04 +0300 Subject: [PATCH 6/6] AUR: Fix hwnd redefinition @@ -48,5 +48,5 @@ index 627fbbb4..3b3ccf15 100644 WINE_DEFAULT_DEBUG_CHANNEL(vrclient); -- -2.43.0 +2.43.1 diff --git a/proton-cachyos/PKGBUILD b/proton-cachyos/PKGBUILD index 63368472..b1560f23 100644 --- a/proton-cachyos/PKGBUILD +++ b/proton-cachyos/PKGBUILD @@ -7,7 +7,7 @@ _optimize=${_optimize-y} _optimize_v4=${_optimize_v4-} pkgname=proton-cachyos -_srctag=8.0-20231219 +_srctag=8.0-80590-20240215-p002645-w191c4e-d9491b5-ve64116 _commit= pkgver=8.0 # pkgver=${_srctag//-/.} @@ -33,7 +33,7 @@ depends=( lzo lib32-lzo libxkbcommon lib32-libxkbcommon libvpx lib32-libvpx - 'sdl2>=2.0.16' 'lib32-sdl2>=2.0.16' + sdl2 lib32-sdl2 libsoup lib32-libsoup libgudev lib32-libgudev blas lib32-blas @@ -92,7 +92,7 @@ makedepends=(${makedepends[@]} ${depends[@]}) provides=('proton') install=${pkgname}.install source=( - proton::git+https://github.com/ValveSoftware/Proton.git#tag=experimental-${_srctag} + proton::git+https://github.com/ValveSoftware/Proton.git#tag=experimental-bleeding-edge-${_srctag} https://dl.winehq.org/wine/wine-gecko/${_geckover}/wine-gecko-${_geckover}-x86{,_64}.tar.xz https://github.com/madewokherd/wine-mono/releases/download/wine-mono-${_monover}/wine-mono-${_monover}-x86.tar.xz 0001-AUR-Pkgbuild-changes.patch @@ -198,9 +198,10 @@ prepare() { cd $srcdir/proton/dxvk echo "dxvk: Enable Reflex" patch -Np1 -i "$srcdir"/dxvk-reflex.patch - patch -Np1 -i "$srcdir"/dxvk-reflex-lockfix.patch +# patch -Np1 -i "$srcdir"/dxvk-reflex-lockfix.patch echo "dxvk-nvapi: Enable Reflex" cd $srcdir/proton/dxvk-nvapi + git checkout 0a7c48b256cafe6b3fa1db8183f089712c72e9ad patch -Np1 -i "$srcdir"/nvapi-reflex.patch echo "vkd3d-proton: Enable-Reflex" @@ -208,10 +209,10 @@ prepare() { patch -Np1 -i "$srcdir"/vkd3d-reflex.patch cd $srcdir/proton/dxvk/include/vulkan - git checkout bbe0f575ebd6098369f0ac6c6a43532732ed0ba6 + git checkout 5a5c9a643484d888873e32c5d7d484fae8e71d3d echo "Update Vulkan Headers for vkd3d-proton" cd $srcdir/proton/vkd3d-proton/khronos/Vulkan-Headers - git checkout bbe0f575ebd6098369f0ac6c6a43532732ed0ba6 + git checkout 5a5c9a643484d888873e32c5d7d484fae8e71d3d } @@ -305,19 +306,19 @@ sha256sums=('SKIP' '2cfc8d5c948602e21eff8a78613e1826f2d033df9672cace87fed56e8310afb6' 'fd88fc7e537d058d7a8abf0c1ebc90c574892a466de86706a26d254710a82814' '4e3e8a40729e4c9e3e9e651cebe4f1aed8f9a4d22e991e6cd24608687f0eedd4' - '9dffdab7d53dc81ab82ba86d1f4baa8f85b1fe0410ece76b89295b09aab7fbe0' - 'f16e8271169cbaca1111e925a02bd0d1dfcfd6a0941435b724734b626689f6c6' + 'facdd6c59e93f5f0877ba1e68a1f5f90f8cd8333e6fba863760ddfa49330753c' + '0ad87e3ca616120ec490361df41e24b445a62ad4f9652b048d156c4859f4a2f6' '369193510b9309fc9cb80fc204220599583677a59976c7f434c2a33871b0cbe1' - '42c869c47a3079087125efa94d786c5942cbd518a7ab087770a5c19d2007e0d6' - '0892daec01d88ae497d1389673931f5aa1a93de56b24eeee6a6beaefcee8943c' - 'c589f9bf60c27033680036a048374632001eddf8a9ca2277c7ed5893263c2ac9' - 'eefb327133ee164db6d8002a851b8fad72f9fc2e669f1d58901ebdadbc240823' + 'e76d56f97a795f143ecd718229b9af8a5e2a4d1daffa6e35a26bc68c1c22f68e' + 'a5429443e20a2b5d5f1e90626741b264bac036556202f99c691637815785c989' + '73fabb8d30e174e57ac864a5ec7a3bc6bcd0fd917db4094d3b9ad807ca69a411' + 'db9f7cca780b4e4225e1cc75501cd348878112936cdc5c832caa8e4dd6614e1a' 'd84f6530acd6d6480fa15cc566665ca2a5af98dbe1b66b4a9295bd186a685585' '2f30e393b5e6c371a68ad6b5b6693d35412d30ba7e3963bc65a650c9c29ff569' - '6464b6a08aa8b117e7395e3a0dcf8d7434936962e790505143446557a7f1d2da' + 'ceff1ff8de8bc25729cc7928eb46d16ef4c2f49ef3eb2e47ce3134337ca7107e' 'ac757218883c65f563e5a211dfbc1be477b9f39e0bba5cd89ae2c867619e5ce3' '80322501d28cc3f288fe206e4e943b5b8a579993f15227ad4f7ce5d879af0d54' - 'cda9aee7a4cb76a4c85705ccc9c06df0c0e982080111eb884246abfa97d1253a' + '21b854b0a78a142c182faabeaed140abeaee88d754fe5ce84a63433a71fd67ed' '08af47c4597b9cb5e7984eb7e273d03ba7c205eb4a72f4f91329e5e1d60e90a7' '23e35740995ada449865b0b5129e8177e995d28842a924be4562e65d6513bafd' 'bd0482c05474068bb50a176eb33c02a1eb3ac1bece0365ee0dd3bcd304fabf9e') diff --git a/proton-cachyos/dxvk-reflex.patch b/proton-cachyos/dxvk-reflex.patch index 2300e643..740d56d2 100644 --- a/proton-cachyos/dxvk-reflex.patch +++ b/proton-cachyos/dxvk-reflex.patch @@ -1,4 +1,4 @@ -From 2518e1c71e64679be3f38c622f8294e9354e44a0 Mon Sep 17 00:00:00 2001 +From d0e232c506d23b9d5f4765e1bc6bfc984fd4b81c Mon Sep 17 00:00:00 2001 From: Eric Sullivan Date: Mon, 9 Oct 2023 01:51:16 -0700 Subject: [PATCH] Add VK_NV_low_latency2 support @@ -6,27 +6,30 @@ Subject: [PATCH] Add VK_NV_low_latency2 support This commit add support for the VK_NV_low_latency2 extension, and implements the ID3DLowLatencyDevice interface. --- - src/d3d11/d3d11_device.cpp | 168 +++++++++++++++++++++++++++++++--- - src/d3d11/d3d11_device.h | 82 ++++++++++++++--- - src/d3d11/d3d11_interfaces.h | 58 +++++++++++- - src/d3d11/d3d11_swapchain.cpp | 36 +++++++- - src/d3d11/d3d11_swapchain.h | 18 +++- - src/dxvk/dxvk_adapter.cpp | 13 ++- - src/dxvk/dxvk_cmdlist.cpp | 17 +++- - src/dxvk/dxvk_cmdlist.h | 5 +- - src/dxvk/dxvk_device.cpp | 2 + - src/dxvk/dxvk_device.h | 51 ++++++++++- - src/dxvk/dxvk_device_info.h | 3 +- - src/dxvk/dxvk_extensions.h | 1 + - src/dxvk/dxvk_presenter.cpp | 99 +++++++++++++++++++- - src/dxvk/dxvk_presenter.h | 43 +++++++++ - src/dxvk/dxvk_queue.cpp | 4 +- - src/dxvk/dxvk_queue.h | 1 + - src/vulkan/vulkan_loader.h | 8 ++ - 17 files changed, 563 insertions(+), 46 deletions(-) + src/d3d11/d3d11_device.cpp | 171 ++++++++++++++++++++++++++++---- + src/d3d11/d3d11_device.h | 78 +++++++++++++-- + src/d3d11/d3d11_initializer.cpp | 2 +- + src/d3d11/d3d11_interfaces.h | 56 +++++++++++ + src/d3d11/d3d11_swapchain.cpp | 51 +++++++++- + src/d3d11/d3d11_swapchain.h | 18 +++- + src/dxvk/dxvk_adapter.cpp | 13 ++- + src/dxvk/dxvk_cmdlist.cpp | 17 +++- + src/dxvk/dxvk_cmdlist.h | 5 +- + src/dxvk/dxvk_context.cpp | 4 +- + src/dxvk/dxvk_context.h | 3 +- + src/dxvk/dxvk_device.cpp | 6 +- + src/dxvk/dxvk_device.h | 55 +++++++++- + src/dxvk/dxvk_device_info.h | 3 +- + src/dxvk/dxvk_extensions.h | 1 + + src/dxvk/dxvk_presenter.cpp | 132 +++++++++++++++++++++++- + src/dxvk/dxvk_presenter.h | 45 +++++++++ + src/dxvk/dxvk_queue.cpp | 4 +- + src/dxvk/dxvk_queue.h | 1 + + src/vulkan/vulkan_loader.h | 8 ++ + 20 files changed, 618 insertions(+), 55 deletions(-) diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp -index 9398e484208..22760b48922 100644 +index 9398e484208..db0d5faf26f 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -15,6 +15,7 @@ @@ -54,10 +57,12 @@ index 9398e484208..22760b48922 100644 bool STDMETHODCALLTYPE D3D11DeviceExt::GetCudaTextureObjectNVX(uint32_t srvDriverHandle, uint32_t samplerDriverHandle, uint32_t* pCudaTextureHandle) { ID3D11ShaderResourceView* srv = HandleToSrvNVX(srvDriverHandle); -@@ -2783,8 +2786,133 @@ namespace dxvk { +@@ -2783,8 +2786,132 @@ namespace dxvk { +- +- + + D3D11LowLatencyDevice::D3D11LowLatencyDevice( + D3D11DXGIDevice* pContainer, @@ -65,28 +70,30 @@ index 9398e484208..22760b48922 100644 + : m_container(pContainer), m_device(pDevice) { + + } - - ++ ++ + ULONG STDMETHODCALLTYPE D3D11LowLatencyDevice::AddRef() { + return m_container->AddRef(); + } -+ -+ ++ ++ + ULONG STDMETHODCALLTYPE D3D11LowLatencyDevice::Release() { + return m_container->Release(); + } -+ -+ ++ ++ + HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::QueryInterface( + REFIID riid, + void** ppvObject) { + return m_container->QueryInterface(riid, ppvObject); + } + ++ + BOOL STDMETHODCALLTYPE D3D11LowLatencyDevice::SupportsLowLatency() { + return m_device->GetDXVKDevice()->features().nvLowLatency2; + } + ++ + HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::LatencySleep() { + if (!m_device->GetDXVKDevice()->features().nvLowLatency2) { + return E_NOINTERFACE; @@ -94,15 +101,13 @@ index 9398e484208..22760b48922 100644 + + D3D11SwapChain* pSwapChain = m_device->GetLowLatencySwapChain(); + if (pSwapChain && pSwapChain->LowLatencyEnabled()) { -+ VkResult res = pSwapChain->LatencySleep(); -+ if (res != VK_SUCCESS) { -+ return S_FALSE; -+ } ++ pSwapChain->LatencySleep(); + } + + return S_OK; + } + ++ + HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::SetLatencySleepMode(BOOL lowLatencyMode, BOOL lowLatencyBoost, uint32_t minimumIntervalUs) { + if (!m_device->GetDXVKDevice()->features().nvLowLatency2) { + return E_NOINTERFACE; @@ -110,15 +115,13 @@ index 9398e484208..22760b48922 100644 + + D3D11SwapChain* pSwapChain = m_device->GetLowLatencySwapChain(); + if (pSwapChain) { -+ VkResult res = pSwapChain->SetLatencySleepMode(lowLatencyMode, lowLatencyBoost, minimumIntervalUs); -+ if (res != VK_SUCCESS) { -+ return S_FALSE; -+ } ++ pSwapChain->SetLatencySleepMode(lowLatencyMode, lowLatencyBoost, minimumIntervalUs); + } + + return S_OK; + } + ++ + HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::SetLatencyMarker(uint64_t frameID, uint32_t markerType) { + if (!m_device->GetDXVKDevice()->features().nvLowLatency2) { + return E_NOINTERFACE; @@ -137,6 +140,7 @@ index 9398e484208..22760b48922 100644 + return S_OK; + } + ++ + HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::GetLatencyInfo(D3D11_LATENCY_RESULTS* latencyResults) + { + if (!m_device->GetDXVKDevice()->features().nvLowLatency2) { @@ -188,7 +192,7 @@ index 9398e484208..22760b48922 100644 D3D11VideoDevice::D3D11VideoDevice( D3D11DXGIDevice* pContainer, D3D11Device* pDevice) -@@ -3021,7 +3149,11 @@ namespace dxvk { +@@ -3021,7 +3148,11 @@ namespace dxvk { Com presenter = new D3D11SwapChain( m_container, m_device, pSurfaceFactory, pDesc); @@ -201,7 +205,7 @@ index 9398e484208..22760b48922 100644 *ppSwapChain = presenter.ref(); return S_OK; } catch (const DxvkError& e) { -@@ -3078,17 +3210,18 @@ namespace dxvk { +@@ -3078,17 +3209,18 @@ namespace dxvk { Rc pDxvkDevice, D3D_FEATURE_LEVEL FeatureLevel, UINT FeatureFlags) @@ -231,7 +235,7 @@ index 9398e484208..22760b48922 100644 } -@@ -3142,7 +3275,12 @@ namespace dxvk { +@@ -3142,7 +3274,12 @@ namespace dxvk { *ppvObject = ref(&m_d3d11DeviceExt); return S_OK; } @@ -246,7 +250,7 @@ index 9398e484208..22760b48922 100644 *ppvObject = ref(&m_metaDevice); return S_OK; diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h -index 7a44b5ad99c..7372bbec168 100644 +index 7a44b5ad99c..c04fcd75768 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -24,6 +24,7 @@ @@ -257,7 +261,7 @@ index 7a44b5ad99c..7372bbec168 100644 #include "d3d11_util.h" namespace dxvk { -@@ -428,6 +429,22 @@ namespace dxvk { +@@ -428,6 +429,18 @@ namespace dxvk { bool Is11on12Device() const; @@ -266,21 +270,17 @@ index 7a44b5ad99c..7372bbec168 100644 + } + + void RemoveSwapchain(D3D11SwapChain* swapchain) { -+ std::remove(m_swapchains.begin(), m_swapchains.end(), swapchain); -+ } -+ -+ UINT GetSwapchainCount() { -+ return m_swapchains.size(); ++ m_swapchains.erase(std::remove(m_swapchains.begin(), m_swapchains.end(), swapchain)); + } + + D3D11SwapChain* GetLowLatencySwapChain() { -+ return (m_swapchains.size()) == 1 ? m_swapchains[0] : nullptr; ++ return (m_swapchains.size() == 1) ? m_swapchains[0] : nullptr; + } + static D3D_FEATURE_LEVEL GetMaxFeatureLevel( const Rc& Instance, const Rc& Adapter); -@@ -464,6 +481,8 @@ namespace dxvk { +@@ -464,6 +477,8 @@ namespace dxvk { D3D_FEATURE_LEVEL m_maxFeatureLevel; D3D11DeviceFeatures m_deviceFeatures; @@ -289,7 +289,7 @@ index 7a44b5ad99c..7372bbec168 100644 HRESULT CreateShaderModule( D3D11CommonShader* pShaderModule, DxvkShaderKey ShaderKey, -@@ -545,28 +564,28 @@ namespace dxvk { +@@ -545,28 +560,28 @@ namespace dxvk { uint64_t* gpuVAStart, uint64_t* gpuVASize); @@ -323,7 +323,7 @@ index 7a44b5ad99c..7372bbec168 100644 void AddSamplerAndHandleNVX( ID3D11SamplerState* pSampler, uint32_t Handle); -@@ -586,6 +605,46 @@ namespace dxvk { +@@ -586,6 +601,46 @@ namespace dxvk { std::unordered_map m_srvHandleToPtr; }; @@ -370,7 +370,7 @@ index 7a44b5ad99c..7372bbec168 100644 /** * \brief D3D11 video device -@@ -856,12 +915,13 @@ namespace dxvk { +@@ -856,12 +911,13 @@ namespace dxvk { Rc m_dxvkAdapter; Rc m_dxvkDevice; @@ -390,8 +390,21 @@ index 7a44b5ad99c..7372bbec168 100644 DXGIVkSwapChainFactory m_dxvkFactory; +diff --git a/src/d3d11/d3d11_initializer.cpp b/src/d3d11/d3d11_initializer.cpp +index 105485fabb9..9a97905fab6 100644 +--- a/src/d3d11/d3d11_initializer.cpp ++++ b/src/d3d11/d3d11_initializer.cpp +@@ -280,7 +280,7 @@ namespace dxvk { + + + void D3D11Initializer::FlushInternal() { +- m_context->flushCommandList(nullptr); ++ m_context->flushCommandList(nullptr, false); + + m_transferCommands = 0; + m_transferMemory = 0; diff --git a/src/d3d11/d3d11_interfaces.h b/src/d3d11/d3d11_interfaces.h -index 587cde1394e..49b301b0fdb 100644 +index 8a2e6fcf4ff..f33eb6f34e2 100644 --- a/src/d3d11/d3d11_interfaces.h +++ b/src/d3d11/d3d11_interfaces.h @@ -16,6 +16,7 @@ enum D3D11_VK_EXTENSION : uint32_t { @@ -470,66 +483,74 @@ index 587cde1394e..49b301b0fdb 100644 /** * \brief Extended D3D11 context -@@ -182,17 +237,18 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext { - uint32_t numWriteResources) = 0; - }; - -- - #ifdef _MSC_VER - struct __declspec(uuid("bb8a4fb9-3935-4762-b44b-35189a26414a")) ID3D11VkExtShader; - struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice; - struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1; - struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext; - struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1; -+struct __declspec(uuid("f3112584-41f9-348d-a59b-00b7e1d285d6")) ID3DLowLatencyDevice; - #else - __CRT_UUID_DECL(ID3D11VkExtShader, 0xbb8a4fb9,0x3935,0x4762,0xb4,0x4b,0x35,0x18,0x9a,0x26,0x41,0x4a); - __CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17); +@@ -189,4 +244,5 @@ __CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0x __CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06); __CRT_UUID_DECL(ID3D11VkExtContext, 0xfd0bca13,0x5cb6,0x4c3a,0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91); __CRT_UUID_DECL(ID3D11VkExtContext1, 0x874b09b2,0xae0b,0x41d8,0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d); +__CRT_UUID_DECL(ID3DLowLatencyDevice, 0xf3112584,0x41f9,0x348d,0xa5,0x9b,0x00,0xb7,0xe1,0xd2,0x85,0xd6); #endif diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp -index 0e823f410ef..4faffa00e48 100644 +index 0e823f410ef..ac42b288adf 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp -@@ -351,6 +351,34 @@ namespace dxvk { - *pFrameStatistics = m_frameStatistics; +@@ -84,7 +84,11 @@ namespace dxvk { + + m_device->waitForSubmission(&m_presentStatus); + m_device->waitForIdle(); +- ++ ++ if (m_device->features().nvLowLatency2) { ++ m_parent->RemoveSwapchain(this); ++ } ++ + DestroyFrameLatencyEvent(); } -+ VkResult D3D11SwapChain::SetLatencySleepMode( +@@ -352,6 +356,43 @@ namespace dxvk { + } + + ++ void D3D11SwapChain::SetLatencySleepMode( + bool lowLatencyMode, + bool lowLatencyBoost, + uint32_t minimumIntervalUs) { -+ if (lowLatencyMode && !LowLatencyEnabled()) { -+ RecreateSwapChain(); -+ } -+ return m_presenter->setLatencySleepMode(lowLatencyMode, lowLatencyBoost, minimumIntervalUs); ++ m_presenter->setLatencySleepMode(lowLatencyMode, lowLatencyBoost, minimumIntervalUs); ++ ++ // The swapchain will have its low latency state updated ++ // when it gets recreated. The swapchain needs to be recreated ++ // to ensure we can use the frameId provided by the application ++ // as a presentId as presentation time. ++ m_dirty = true; + } + -+ VkResult D3D11SwapChain::LatencySleep() { -+ return m_presenter->latencySleep(); ++ ++ void D3D11SwapChain::LatencySleep() { ++ m_presenter->latencySleep(); + } + ++ + void D3D11SwapChain::SetLatencyMarker( + VkLatencyMarkerNV marker, + uint64_t presentId) { + m_presenter->setLatencyMarker(marker, presentId); + } + -+ VkResult D3D11SwapChain::GetLatencyTimings( ++ ++ void D3D11SwapChain::GetLatencyTimings( + std::vector& frameReports) { -+ return m_presenter->getLatencyTimings(frameReports); ++ m_presenter->getLatencyTimings(frameReports); + } + ++ + bool D3D11SwapChain::LowLatencyEnabled() { + return m_presenter->lowLatencyEnabled(); + } - ++ ++ HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) { // Flush pending rendering commands before -@@ -410,9 +438,11 @@ namespace dxvk { + auto immediateContext = m_parent->GetContext(); +@@ -410,9 +451,11 @@ namespace dxvk { uint32_t Repeat) { auto lock = pContext->LockContext(); @@ -545,25 +566,25 @@ index 0e823f410ef..4faffa00e48 100644 // Present from CS thread so that we don't // have to synchronize with it first. diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h -index 00073d7690e..a3ecf634381 100644 +index 00073d7690e..508f7aafa20 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -86,6 +86,22 @@ namespace dxvk { void STDMETHODCALLTYPE GetFrameStatistics( DXGI_VK_FRAME_STATISTICS* pFrameStatistics); -+ VkResult SetLatencySleepMode( ++ void SetLatencySleepMode( + bool lowLatencyMode, + bool lowLatencyBoost, + uint32_t minimumIntervalUs); + -+ VkResult LatencySleep(); ++ void LatencySleep(); + + void SetLatencyMarker( + VkLatencyMarkerNV marker, + uint64_t presentId); + -+ VkResult GetLatencyTimings( ++ void GetLatencyTimings( + std::vector& frameReports); + + bool LowLatencyEnabled(); @@ -713,8 +734,39 @@ index b9b9a165dd3..f9527516e17 100644 /** * \brief Stat counters +diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp +index 80c2620de8e..f80ef9954b2 100644 +--- a/src/dxvk/dxvk_context.cpp ++++ b/src/dxvk/dxvk_context.cpp +@@ -105,9 +105,9 @@ namespace dxvk { + } + + +- void DxvkContext::flushCommandList(DxvkSubmitStatus* status) { ++ void DxvkContext::flushCommandList(DxvkSubmitStatus* status, bool enableFrameId) { + m_device->submitCommandList( +- this->endRecording(), status); ++ this->endRecording(), status, enableFrameId); + + this->beginRecording( + m_device->createCommandList()); +diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h +index 93ed91e3603..0d1d094b074 100644 +--- a/src/dxvk/dxvk_context.h ++++ b/src/dxvk/dxvk_context.h +@@ -65,8 +65,9 @@ namespace dxvk { + * Transparently submits the current command + * buffer and allocates a new one. + * \param [out] status Submission feedback ++ * \param [in] enableFrameId Submission should include the frame id + */ +- void flushCommandList(DxvkSubmitStatus* status); ++ void flushCommandList(DxvkSubmitStatus* status, bool enableFrameId = true); + + /** + * \brief Begins generating query data diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp -index 9a053791a7b..44d208c41aa 100644 +index 9a053791a7b..1e2c34b958c 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -18,6 +18,7 @@ namespace dxvk { @@ -725,16 +777,22 @@ index 9a053791a7b..44d208c41aa 100644 m_queues (queues), m_submissionQueue (this, queueCallback) { -@@ -274,6 +275,7 @@ namespace dxvk { - DxvkSubmitStatus* status) { +@@ -271,9 +272,12 @@ namespace dxvk { + + void DxvkDevice::submitCommandList( + const Rc& commandList, +- DxvkSubmitStatus* status) { ++ DxvkSubmitStatus* status, ++ bool enableFrameId) { DxvkSubmitInfo submitInfo = { }; submitInfo.cmdList = commandList; -+ submitInfo.frameId = m_latencyMarkers.render; ++ submitInfo.frameId = enableFrameId ? ++ m_latencyMarkers.render : 0; m_submissionQueue.submit(submitInfo, status); std::lock_guard statLock(m_statLock); diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h -index a24ee311bf5..cfef76a0874 100644 +index a24ee311bf5..305e6e00efb 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -66,7 +66,16 @@ namespace dxvk { @@ -755,7 +813,21 @@ index a24ee311bf5..cfef76a0874 100644 /** * \brief DXVK device * -@@ -534,6 +543,44 @@ namespace dxvk { +@@ -471,10 +480,12 @@ namespace dxvk { + * the given set of optional synchronization primitives. + * \param [in] commandList The command list to submit + * \param [out] status Submission feedback ++ * \param [in] enableFrameId Submission should include the frame id + */ + void submitCommandList( + const Rc& commandList, +- DxvkSubmitStatus* status); ++ DxvkSubmitStatus* status, ++ bool enableFrameId = true); + + /** + * \brief Locks submission queue +@@ -534,6 +545,44 @@ namespace dxvk { * used by the GPU can be safely destroyed. */ void waitForIdle(); @@ -800,7 +872,7 @@ index a24ee311bf5..cfef76a0874 100644 private: -@@ -549,6 +596,8 @@ namespace dxvk { +@@ -549,6 +598,8 @@ namespace dxvk { DxvkDevicePerfHints m_perfHints; DxvkObjects m_objects; @@ -827,7 +899,7 @@ index e23a0e1812e..ec0bc5a645e 100644 \ No newline at end of file +} diff --git a/src/dxvk/dxvk_extensions.h b/src/dxvk/dxvk_extensions.h -index 8164ccf6ad6..041d00c3cee 100644 +index ae4c8a74f0a..acd5faf56be 100644 --- a/src/dxvk/dxvk_extensions.h +++ b/src/dxvk/dxvk_extensions.h @@ -325,6 +325,7 @@ namespace dxvk { @@ -839,7 +911,7 @@ index 8164ccf6ad6..041d00c3cee 100644 DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled }; }; diff --git a/src/dxvk/dxvk_presenter.cpp b/src/dxvk/dxvk_presenter.cpp -index 10f13da2783..9f7c6a0def0 100644 +index 10f13da2783..b89eddef323 100644 --- a/src/dxvk/dxvk_presenter.cpp +++ b/src/dxvk/dxvk_presenter.cpp @@ -18,6 +18,15 @@ namespace dxvk { @@ -858,21 +930,7 @@ index 10f13da2783..9f7c6a0def0 100644 } -@@ -48,6 +57,7 @@ namespace dxvk { - - - VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) { -+ std::lock_guard lock(m_lowLatencyMutex); - sync = m_semaphores.at(m_frameIndex); - - // Don't acquire more than one image at a time -@@ -68,11 +78,13 @@ namespace dxvk { - VkResult Presenter::presentImage( - VkPresentModeKHR mode, - uint64_t frameId) { -+ std::lock_guard lock(m_lowLatencyMutex); -+ - PresenterSync sync = m_semaphores.at(m_frameIndex); +@@ -72,7 +81,7 @@ namespace dxvk { VkPresentIdKHR presentId = { VK_STRUCTURE_TYPE_PRESENT_ID_KHR }; presentId.swapchainCount = 1; @@ -881,16 +939,52 @@ index 10f13da2783..9f7c6a0def0 100644 VkSwapchainPresentModeInfoEXT modeInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT }; modeInfo.swapchainCount = 1; -@@ -151,6 +163,8 @@ namespace dxvk { +@@ -88,8 +97,11 @@ namespace dxvk { + if (m_device->features().khrPresentId.presentId && frameId) + presentId.pNext = const_cast(std::exchange(info.pNext, &presentId)); + +- if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1) ++ if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1) { ++ if (m_device->features().nvLowLatency2) ++ m_presentSupportsLowLatency = std::find(m_lowLatencyModes.begin(), m_lowLatencyModes.end(), mode) != m_lowLatencyModes.end(); + modeInfo.pNext = const_cast(std::exchange(info.pNext, &modeInfo)); ++ } + VkResult status = m_vkd->vkQueuePresentKHR( + m_device->queues().graphics.queueHandle, &info); +@@ -173,6 +185,7 @@ namespace dxvk { - VkResult Presenter::recreateSwapChain(const PresenterDesc& desc) { -+ std::lock_guard lock(m_lowLatencyMutex); + std::vector formats; + std::vector modes; ++ std::vector lowLatencyModes; + + VkResult status; + +@@ -283,6 +296,23 @@ namespace dxvk { + dynamicModes.clear(); + } + ++ if (m_device->features().nvLowLatency2) { ++ VkLatencySurfaceCapabilitiesNV latencySurfaceCaps { VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV }; + - if (m_swapchain) - destroySwapchain(); ++ caps.pNext = &latencySurfaceCaps; ++ ++ if((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilities2KHR(m_device->adapter()->handle(), &surfaceInfo, &caps))) ++ return status; ++ ++ lowLatencyModes.resize(latencySurfaceCaps.presentModeCount); ++ latencySurfaceCaps.pPresentModes = lowLatencyModes.data(); ++ ++ if ((status = m_vki->vkGetPhysicalDeviceSurfaceCapabilities2KHR(m_device->adapter()->handle(), &surfaceInfo, &caps))) ++ return status; ++ ++ caps.pNext = nullptr; ++ } ++ + // Compute swap chain image count based on available info + m_info.imageCount = pickImageCount(minImageCount, maxImageCount, desc.imageCount); -@@ -293,6 +307,9 @@ namespace dxvk { +@@ -293,6 +323,9 @@ namespace dxvk { modeInfo.presentModeCount = compatibleModes.size(); modeInfo.pPresentModes = compatibleModes.data(); @@ -900,7 +994,7 @@ index 10f13da2783..9f7c6a0def0 100644 VkSwapchainCreateInfoKHR swapInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; swapInfo.surface = m_surface; swapInfo.minImageCount = m_info.imageCount; -@@ -314,6 +331,9 @@ namespace dxvk { +@@ -314,6 +347,9 @@ namespace dxvk { if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1) modeInfo.pNext = std::exchange(swapInfo.pNext, &modeInfo); @@ -910,7 +1004,7 @@ index 10f13da2783..9f7c6a0def0 100644 Logger::info(str::format( "Presenter: Actual swap chain properties:" "\n Format: ", m_info.format.format, -@@ -322,11 +342,21 @@ namespace dxvk { +@@ -322,11 +358,29 @@ namespace dxvk { "\n Buffer size: ", m_info.imageExtent.width, "x", m_info.imageExtent.height, "\n Image count: ", m_info.imageCount, "\n Exclusive FS: ", desc.fullScreenExclusive)); @@ -922,6 +1016,11 @@ index 10f13da2783..9f7c6a0def0 100644 - + + if (m_device->features().nvLowLatency2) { ++ std::lock_guard lock(m_lowLatencyMutex); ++ ++ if (!m_lowLatencyEnabled) ++ m_device->resetLatencyMarkers(); ++ + VkLatencySleepModeInfoNV sleepModeInfo = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV }; + sleepModeInfo.lowLatencyMode = m_lowLatencyEnabled; + sleepModeInfo.lowLatencyBoost = m_lowLatencyBoost; @@ -929,35 +1028,42 @@ index 10f13da2783..9f7c6a0def0 100644 + + if ((status = m_vkd->vkSetLatencySleepModeNV(m_vkd->device(), m_swapchain, &sleepModeInfo))) + return status; ++ ++ m_presentSupportsLowLatency = std::find( ++ lowLatencyModes.begin(), lowLatencyModes.end(), m_info.presentMode) != lowLatencyModes.end(); + } + // Acquire images and create views std::vector images; -@@ -422,6 +452,69 @@ namespace dxvk { - m_vkd->vkSetHdrMetadataEXT(m_vkd->device(), 1, &m_swapchain, &hdrMetadata); +@@ -377,6 +431,7 @@ namespace dxvk { + m_acquireStatus = VK_NOT_READY; + + m_dynamicModes = std::move(dynamicModes); ++ m_lowLatencyModes = std::move(lowLatencyModes); + return VK_SUCCESS; + } + +@@ -423,6 +478,73 @@ namespace dxvk { } -+ VkResult Presenter::setLatencySleepMode(bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs) { -+ VkLatencySleepModeInfoNV sleepModeInfo = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV }; -+ sleepModeInfo.lowLatencyMode = lowLatencyMode; -+ sleepModeInfo.lowLatencyBoost = lowLatencyBoost; -+ sleepModeInfo.minimumIntervalUs = minimumIntervalUs; + ++ void Presenter::setLatencySleepMode(bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs) { ++ if (lowLatencyMode == m_lowLatencyEnabled ++ && lowLatencyBoost == m_lowLatencyBoost ++ && minimumIntervalUs == m_minimumIntervalUs) { ++ return; ++ } + + std::lock_guard lock(m_lowLatencyMutex); -+ VkResult status = m_vkd->vkSetLatencySleepModeNV(m_vkd->device(), m_swapchain, &sleepModeInfo); + + m_lowLatencyEnabled = lowLatencyMode; + m_lowLatencyBoost = lowLatencyBoost; + m_minimumIntervalUs = minimumIntervalUs; -+ -+ if (!lowLatencyMode) -+ m_device->resetLatencyMarkers(); -+ -+ return status; + } + -+ VkResult Presenter::latencySleep() { ++ ++ void Presenter::latencySleep() { + VkSemaphore sem = m_lowLatencyFence.fence->handle(); + uint64_t waitValue = m_lowLatencyFence.value + 1; + m_lowLatencyFence.value++; @@ -966,46 +1072,63 @@ index 10f13da2783..9f7c6a0def0 100644 + sleepInfo.signalSemaphore = sem; + sleepInfo.value = waitValue; + ++ bool shouldSleep = false; ++ + { + std::lock_guard lock(m_lowLatencyMutex); -+ m_vkd->vkLatencySleepNV(m_vkd->device(), m_swapchain, &sleepInfo); ++ if (m_swapchain) { ++ shouldSleep = true; ++ m_vkd->vkLatencySleepNV(m_vkd->device(), m_swapchain, &sleepInfo); ++ } + } + -+ m_lowLatencyFence.fence->wait(waitValue); -+ -+ return VK_SUCCESS; ++ if (shouldSleep) ++ m_lowLatencyFence.fence->wait(waitValue); + } + ++ + void Presenter::setLatencyMarker(VkLatencyMarkerNV marker, uint64_t presentId) { + VkSetLatencyMarkerInfoNV markerInfo = { VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV }; + markerInfo.presentID = presentId; + markerInfo.marker = marker; + + std::lock_guard lock(m_lowLatencyMutex); -+ m_vkd->vkSetLatencyMarkerNV(m_vkd->device(), m_swapchain, &markerInfo); ++ if (m_swapchain) ++ m_vkd->vkSetLatencyMarkerNV(m_vkd->device(), m_swapchain, &markerInfo); + } + -+ VkResult Presenter::getLatencyTimings(std::vector& frameReports) { -+ VkGetLatencyMarkerInfoNV markerInfo = { VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV }; -+ uint32_t timingCount = 0; + ++ void Presenter::getLatencyTimings(std::vector& frameReports) { + std::lock_guard lock(m_lowLatencyMutex); -+ m_vkd->vkGetLatencyTimingsNV(m_vkd->device(), m_swapchain, &timingCount, &markerInfo); ++ ++ if (m_swapchain) { ++ VkGetLatencyMarkerInfoNV markerInfo = { VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV }; ++ m_vkd->vkGetLatencyTimingsNV(m_vkd->device(), m_swapchain, &markerInfo); + -+ if (timingCount != 0) { -+ frameReports.resize(timingCount, { VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV }); -+ markerInfo.pTimings = frameReports.data(); ++ if (markerInfo.timingCount != 0) { ++ frameReports.resize(markerInfo.timingCount, { VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV }); ++ markerInfo.pTimings = frameReports.data(); + -+ m_vkd->vkGetLatencyTimingsNV(m_vkd->device(), m_swapchain, &timingCount, &markerInfo); ++ m_vkd->vkGetLatencyTimingsNV(m_vkd->device(), m_swapchain, &markerInfo); ++ } + } -+ -+ return VK_SUCCESS; + } - ++ ++ VkResult Presenter::getSupportedFormats(std::vector& formats, VkFullScreenExclusiveEXT fullScreenExclusive) const { uint32_t numFormats = 0; + +@@ -617,6 +739,8 @@ namespace dxvk { + + + void Presenter::destroySwapchain() { ++ std::lock_guard lock(m_lowLatencyMutex); ++ + if (m_signal != nullptr) + m_signal->wait(m_lastFrameId.load(std::memory_order_acquire)); + diff --git a/src/dxvk/dxvk_presenter.h b/src/dxvk/dxvk_presenter.h -index c5ba1273364..aa52b97b4ce 100644 +index c5ba1273364..6918d18ad77 100644 --- a/src/dxvk/dxvk_presenter.h +++ b/src/dxvk/dxvk_presenter.h @@ -15,6 +15,7 @@ @@ -1026,12 +1149,12 @@ index c5ba1273364..aa52b97b4ce 100644 + * \param [in] enableLowLatency Determines if the low latency + * mode should be enabled of disabled + */ -+ VkResult setLatencySleepMode(bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs); ++ void setLatencySleepMode(bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs); + + /** + * \brief Delay rendering work for lower latency + */ -+ VkResult latencySleep(); ++ void latencySleep(); + + /** + * \brief Set a latency marker for the given stage @@ -1047,19 +1170,19 @@ index c5ba1273364..aa52b97b4ce 100644 + * \param [out] latencyInfo The structure to place + * the latency timings into + */ -+ VkResult getLatencyTimings(std::vector& frameReports); ++ void getLatencyTimings(std::vector& frameReports); + + /** + * \brief Returns the low latency enabled state + */ + bool lowLatencyEnabled() { -+ return m_lowLatencyEnabled; ++ return m_lowLatencyEnabled && m_presentSupportsLowLatency; + } + private: Rc m_device; -@@ -237,6 +274,11 @@ namespace dxvk { +@@ -237,10 +274,17 @@ namespace dxvk { VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; @@ -1067,11 +1190,17 @@ index c5ba1273364..aa52b97b4ce 100644 + bool m_lowLatencyEnabled = false; + bool m_lowLatencyBoost = false; + uint32_t m_minimumIntervalUs = 0; ++ bool m_presentSupportsLowLatency = false; + std::vector m_images; std::vector m_semaphores; -@@ -250,6 +292,7 @@ namespace dxvk { + std::vector m_dynamicModes; ++ std::vector m_lowLatencyModes; + + uint32_t m_imageIndex = 0; + uint32_t m_frameIndex = 0; +@@ -250,6 +294,7 @@ namespace dxvk { FpsLimiter m_fpsLimiter; dxvk::mutex m_frameMutex; diff --git a/proton-cachyos/vkd3d-reflex.patch b/proton-cachyos/vkd3d-reflex.patch index fc7c4345..cb140b02 100644 --- a/proton-cachyos/vkd3d-reflex.patch +++ b/proton-cachyos/vkd3d-reflex.patch @@ -1,4 +1,4 @@ -From 189c87cbc3e9fd3732028d950dc5623df7103a57 Mon Sep 17 00:00:00 2001 +From 4f39f59773b786d06296b2aa1102b6bb9d24bf79 Mon Sep 17 00:00:00 2001 From: Eric Sullivan Date: Thu, 7 Sep 2023 09:27:14 -0700 Subject: [PATCH] vkd3d: Add support for VK_NV_low_latency2 @@ -8,26 +8,26 @@ implements the ID3DLowLatencyDevice, and ID3D12CommandQueueExt interfaces. --- include/meson.build | 1 + - include/vkd3d_command_queue_vkd3d_ext.idl | 30 +++ - include/vkd3d_device_vkd3d_ext.idl | 15 ++ - include/vkd3d_vk_includes.h | 34 ++- - libs/vkd3d/command.c | 41 ++- - libs/vkd3d/command_queue_vkd3d_ext.c | 100 +++++++ - libs/vkd3d/device.c | 14 +- - libs/vkd3d/device_vkd3d_ext.c | 158 ++++++++++- + include/vkd3d_command_queue_vkd3d_ext.idl | 30 ++ + include/vkd3d_device_vkd3d_ext.idl | 15 + + include/vkd3d_vk_includes.h | 34 +- + libs/vkd3d/command.c | 70 +++- + libs/vkd3d/command_queue_vkd3d_ext.c | 91 +++++ + libs/vkd3d/device.c | 68 +++- + libs/vkd3d/device_vkd3d_ext.c | 160 +++++++- libs/vkd3d/meson.build | 1 + - libs/vkd3d/swapchain.c | 315 +++++++++++++++++++++- - libs/vkd3d/vkd3d_private.h | 68 ++++- + libs/vkd3d/swapchain.c | 425 +++++++++++++++++++++- + libs/vkd3d/vkd3d_private.h | 75 +++- libs/vkd3d/vulkan_procs.h | 7 + - 12 files changed, 763 insertions(+), 21 deletions(-) + 12 files changed, 940 insertions(+), 37 deletions(-) create mode 100644 include/vkd3d_command_queue_vkd3d_ext.idl create mode 100644 libs/vkd3d/command_queue_vkd3d_ext.c diff --git a/include/meson.build b/include/meson.build -index c58579e9..e6ef1767 100644 +index d7398aed70..be784e635d 100644 --- a/include/meson.build +++ b/include/meson.build -@@ -12,6 +12,7 @@ vkd3d_idl = [ +@@ -13,6 +13,7 @@ vkd3d_idl = [ 'vkd3d_dxgitype.idl', 'vkd3d_swapchain_factory.idl', 'vkd3d_command_list_vkd3d_ext.idl', @@ -37,7 +37,7 @@ index c58579e9..e6ef1767 100644 ] diff --git a/include/vkd3d_command_queue_vkd3d_ext.idl b/include/vkd3d_command_queue_vkd3d_ext.idl new file mode 100644 -index 00000000..3c69f00a +index 0000000000..3c69f00a64 --- /dev/null +++ b/include/vkd3d_command_queue_vkd3d_ext.idl @@ -0,0 +1,30 @@ @@ -72,7 +72,7 @@ index 00000000..3c69f00a + HRESULT NotifyOutOfBandCommandQueue(D3D12_OUT_OF_BAND_CQ_TYPE type); +} diff --git a/include/vkd3d_device_vkd3d_ext.idl b/include/vkd3d_device_vkd3d_ext.idl -index 3e615d76..4a21ba76 100644 +index 3e615d76a1..4a21ba763e 100644 --- a/include/vkd3d_device_vkd3d_ext.idl +++ b/include/vkd3d_device_vkd3d_ext.idl @@ -54,3 +54,18 @@ interface ID3D12DXVKInteropDevice : IUnknown @@ -95,7 +95,7 @@ index 3e615d76..4a21ba76 100644 + HRESULT GetLatencyInfo(D3D12_LATENCY_RESULTS *latency_results); +} diff --git a/include/vkd3d_vk_includes.h b/include/vkd3d_vk_includes.h -index c43e0189..02059613 100644 +index c43e018935..020596130a 100644 --- a/include/vkd3d_vk_includes.h +++ b/include/vkd3d_vk_includes.h @@ -41,9 +41,16 @@ typedef enum VkImageLayout VkImageLayout; @@ -148,10 +148,37 @@ index c43e0189..02059613 100644 #endif // __VKD3D_VK_INCLUDES_H diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c -index a041bcf8..7789dd98 100644 +index a3f7a3adaf..fc73ba7c0b 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c -@@ -15367,12 +15367,14 @@ static struct d3d12_command_list *d3d12_command_list_from_iface(ID3D12CommandLis +@@ -219,6 +219,26 @@ HRESULT vkd3d_queue_create(struct d3d12_device *device, uint32_t family_index, u + return hr; + } + ++void vkd3d_set_queue_out_of_band(struct d3d12_device *device, struct vkd3d_queue *queue) ++{ ++ const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; ++ VkOutOfBandQueueTypeInfoNV queue_info; ++ ++ if (!device->vk_info.NV_low_latency2) ++ return; ++ ++ memset(&queue_info, 0, sizeof(queue_info)); ++ queue_info.sType = VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV; ++ queue_info.pNext = NULL; ++ queue_info.queueType = VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV; ++ ++ VK_CALL(vkQueueNotifyOutOfBandNV(queue->vk_queue, &queue_info)); ++ ++ queue_info.queueType = VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV; ++ ++ VK_CALL(vkQueueNotifyOutOfBandNV(queue->vk_queue, &queue_info)); ++} ++ + static void vkd3d_queue_flush_waiters(struct vkd3d_queue *vkd3d_queue, + struct vkd3d_fence_worker *worker, + const struct vkd3d_vk_device_procs *vk_procs); +@@ -16591,12 +16611,14 @@ static struct d3d12_command_list *d3d12_command_list_from_iface(ID3D12CommandLis } /* ID3D12CommandQueue */ @@ -167,7 +194,7 @@ index a041bcf8..7789dd98 100644 REFIID riid, void **object) { TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); -@@ -15391,6 +15393,14 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_QueryInterface(ID3D12Comman +@@ -16615,6 +16637,14 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_QueryInterface(ID3D12Comman return S_OK; } @@ -182,7 +209,7 @@ index a041bcf8..7789dd98 100644 if (IsEqualGUID(riid, &IID_IDXGIVkSwapChainFactory)) { struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface); -@@ -15405,7 +15415,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_QueryInterface(ID3D12Comman +@@ -16629,7 +16659,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_queue_QueryInterface(ID3D12Comman return E_NOINTERFACE; } @@ -191,7 +218,7 @@ index a041bcf8..7789dd98 100644 { struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface); ULONG refcount = InterlockedIncrement(&command_queue->refcount); -@@ -15415,7 +15425,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_queue_AddRef(ID3D12CommandQueue *if +@@ -16639,7 +16669,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_queue_AddRef(ID3D12CommandQueue *if return refcount; } @@ -200,7 +227,7 @@ index a041bcf8..7789dd98 100644 { struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface); ULONG refcount = InterlockedDecrement(&command_queue->refcount); -@@ -15901,6 +15911,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm +@@ -17132,6 +17162,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm sub.execute.cmd_count = num_command_buffers; sub.execute.command_allocators = allocators; sub.execute.num_command_allocators = command_list_count; @@ -208,7 +235,7 @@ index a041bcf8..7789dd98 100644 #ifdef VKD3D_ENABLE_BREADCRUMBS sub.execute.breadcrumb_indices = breadcrumb_indices; sub.execute.breadcrumb_indices_count = breadcrumb_indices ? command_list_count : 0; -@@ -16063,6 +16074,8 @@ static D3D12_COMMAND_QUEUE_DESC * STDMETHODCALLTYPE d3d12_command_queue_GetDesc( +@@ -17295,6 +17326,8 @@ static D3D12_COMMAND_QUEUE_DESC * STDMETHODCALLTYPE d3d12_command_queue_GetDesc( return desc; } @@ -217,54 +244,60 @@ index a041bcf8..7789dd98 100644 static CONST_VTBL struct ID3D12CommandQueueVtbl d3d12_command_queue_vtbl = { /* IUnknown methods */ -@@ -16570,13 +16583,15 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu - const VkCommandBufferSubmitInfo *transition_cmd, +@@ -17807,10 +17840,12 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu const VkSemaphoreSubmitInfo *transition_semaphore, struct d3d12_command_allocator **command_allocators, size_t num_command_allocators, + struct vkd3d_queue_timeline_trace_cookie timeline_cookie, - bool debug_capture, bool split_submissions) -+ uint64_t frame_id, bool debug_capture, -+ bool split_submissions) ++ uint64_t frame_id, bool debug_capture, bool split_submissions) { const struct vkd3d_vk_device_procs *vk_procs = &command_queue->device->vk_procs; struct vkd3d_queue *vkd3d_queue = command_queue->vkd3d_queue; ++ VkLatencySubmissionPresentIdNV latency_submit_present_info; ++ struct dxgi_vk_swap_chain *low_latency_swapchain; VkSemaphoreSubmitInfo signal_semaphore_info; VkSemaphoreSubmitInfo binary_semaphore_info; VkSubmitInfo2 submit_desc[4]; -+ VkLatencySubmissionPresentIdNV latency_submit_present_info; - uint32_t num_submits; - VkQueue vk_queue; - unsigned int i; -@@ -16656,6 +16671,18 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu +@@ -17895,6 +17930,27 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu num_submits += 2; } -+ if (command_queue->device->vk_info.NV_low_latency2 && -+ command_queue->device->swapchain_info.low_latency_swapchain && -+ dxgi_vk_swap_chain_low_latency_enabled(command_queue->device->swapchain_info.low_latency_swapchain)) ++ if (command_queue->device->vk_info.NV_low_latency2) + { -+ latency_submit_present_info.sType = VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV; -+ latency_submit_present_info.pNext = NULL; -+ latency_submit_present_info.presentID = frame_id; ++ spinlock_acquire(&command_queue->device->low_latency_swapchain_spinlock); ++ if ((low_latency_swapchain = command_queue->device->swapchain_info.low_latency_swapchain)) ++ dxgi_vk_swap_chain_incref(low_latency_swapchain); ++ spinlock_release(&command_queue->device->low_latency_swapchain_spinlock); + -+ for (i = 0; i < num_submits; i++) -+ submit_desc[i].pNext = &latency_submit_present_info; ++ if (low_latency_swapchain && dxgi_vk_swap_chain_low_latency_enabled(low_latency_swapchain)) ++ { ++ latency_submit_present_info.sType = VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV; ++ latency_submit_present_info.pNext = NULL; ++ latency_submit_present_info.presentID = frame_id; ++ ++ for (i = 0; i < num_submits; i++) ++ submit_desc[i].pNext = &latency_submit_present_info; ++ } ++ ++ if (low_latency_swapchain) ++ dxgi_vk_swap_chain_decref(low_latency_swapchain); + } + #ifdef VKD3D_ENABLE_RENDERDOC /* For each submission we have marked to be captured, we will first need to filter it * based on VKD3D_AUTO_CAPTURE_COUNTS. -@@ -17156,7 +17183,9 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata) - &transition_cmd, &transition_semaphore, +@@ -18397,7 +18453,9 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata) submission.execute.command_allocators, submission.execute.num_command_allocators, + submission.execute.timeline_cookie, - submission.execute.debug_capture, submission.execute.split_submission); + submission.execute.frame_id, + submission.execute.debug_capture, + submission.execute.split_submission); - /* command_queue_execute takes ownership of the outstanding_submission_counters allocation. - * The atomic counters are decremented when the submission is observed to be freed. -@@ -17218,6 +17247,7 @@ static HRESULT d3d12_command_queue_init(struct d3d12_command_queue *queue, + /* command_queue_execute takes ownership of the + * outstanding_submission_counters and queue_timeline_indices allocations. +@@ -18460,6 +18518,7 @@ static HRESULT d3d12_command_queue_init(struct d3d12_command_queue *queue, int rc; queue->ID3D12CommandQueue_iface.lpVtbl = &d3d12_command_queue_vtbl; @@ -272,7 +305,7 @@ index a041bcf8..7789dd98 100644 queue->refcount = 1; queue->desc = *desc; -@@ -17346,6 +17376,7 @@ void vkd3d_enqueue_initial_transition(ID3D12CommandQueue *queue, ID3D12Resource +@@ -18588,6 +18647,7 @@ void vkd3d_enqueue_initial_transition(ID3D12CommandQueue *queue, ID3D12Resource memset(&sub, 0, sizeof(sub)); sub.type = VKD3D_SUBMISSION_EXECUTE; @@ -282,10 +315,10 @@ index a041bcf8..7789dd98 100644 sub.execute.transitions[0].type = VKD3D_INITIAL_TRANSITION_TYPE_RESOURCE; diff --git a/libs/vkd3d/command_queue_vkd3d_ext.c b/libs/vkd3d/command_queue_vkd3d_ext.c new file mode 100644 -index 00000000..0fba03b0 +index 0000000000..03e1201149 --- /dev/null +++ b/libs/vkd3d/command_queue_vkd3d_ext.c -@@ -0,0 +1,100 @@ +@@ -0,0 +1,91 @@ +/* + * * Copyright 2023 NVIDIA Corporation + * @@ -342,36 +375,27 @@ index 00000000..0fba03b0 + +static HRESULT STDMETHODCALLTYPE d3d12_command_queue_vkd3d_ext_NotifyOutOfBandCommandQueue(d3d12_command_queue_vkd3d_ext_iface *iface, D3D12_OUT_OF_BAND_CQ_TYPE type) +{ -+ const struct vkd3d_vk_device_procs *vk_procs; -+ struct d3d12_command_queue* command_queue; -+ VkOutOfBandQueueTypeInfoNV queue_info; -+ VkOutOfBandQueueTypeNV queue_type; ++ struct d3d12_command_queue *command_queue; ++ int i; + + command_queue = d3d12_command_queue_from_ID3D12CommandQueueExt(iface); + + if (!command_queue->device->vk_info.NV_low_latency2) + return E_NOTIMPL; + -+ vk_procs = &command_queue->device->vk_procs; ++ if (type != OUT_OF_BAND_RENDER && type != OUT_OF_BAND_PRESENT) ++ return E_INVALIDARG; + -+ switch (type) ++ for (i = 0; i < VKD3D_QUEUE_FAMILY_COUNT; i++) + { -+ case OUT_OF_BAND_RENDER: -+ queue_type = VK_OUT_OF_BAND_QUEUE_TYPE_RENDER_NV; -+ break; -+ case OUT_OF_BAND_PRESENT: -+ queue_type = VK_OUT_OF_BAND_QUEUE_TYPE_PRESENT_NV; ++ if (command_queue->device->queue_families[i]->vk_family_index == command_queue->vkd3d_queue->vk_family_index && ++ command_queue->device->queue_families[i]->out_of_band_queue) ++ { ++ command_queue->vkd3d_queue = command_queue->device->queue_families[i]->out_of_band_queue; + break; -+ default: -+ WARN("Invalid queue type %x\n", type); ++ } + } + -+ queue_info.sType = VK_STRUCTURE_TYPE_OUT_OF_BAND_QUEUE_TYPE_INFO_NV; -+ queue_info.pNext = NULL; -+ queue_info.queueType = queue_type; -+ -+ VK_CALL(vkQueueNotifyOutOfBandNV(command_queue->vkd3d_queue->vk_queue, &queue_info)); -+ + return S_OK; +} + @@ -387,18 +411,135 @@ index 00000000..0fba03b0 +}; + diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c -index c7a1054f..6fe95d48 100644 +index 5701b34456..f48a563d9a 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c -@@ -121,6 +121,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = +@@ -127,6 +127,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] = VK_EXTENSION(NV_SHADER_SUBGROUP_PARTITIONED, NV_shader_subgroup_partitioned), VK_EXTENSION(NV_MEMORY_DECOMPRESSION, NV_memory_decompression), VK_EXTENSION(NV_DEVICE_GENERATED_COMMANDS_COMPUTE, NV_device_generated_commands_compute), -+ VK_EXTENSION(NV_LOW_LATENCY_2, NV_low_latency2), ++ VK_EXTENSION_VERSION(NV_LOW_LATENCY_2, NV_low_latency2, 2), /* VALVE extensions */ VK_EXTENSION(VALVE_MUTABLE_DESCRIPTOR_TYPE, VALVE_mutable_descriptor_type), VK_EXTENSION(VALVE_DESCRIPTOR_SET_HOST_MAPPING, VALVE_descriptor_set_host_mapping), -@@ -3194,8 +3195,9 @@ void d3d12_device_return_query_pool(struct d3d12_device *device, const struct vk +@@ -2588,6 +2589,12 @@ struct vkd3d_device_queue_info + VkDeviceQueueCreateInfo vk_queue_create_info[VKD3D_QUEUE_FAMILY_COUNT]; + }; + ++static bool vkd3d_queue_family_needs_out_of_band_queue(unsigned int vkd3d_queue_family) ++{ ++ return vkd3d_queue_family == VKD3D_QUEUE_FAMILY_GRAPHICS || ++ vkd3d_queue_family == VKD3D_QUEUE_FAMILY_COMPUTE; ++} ++ + static void d3d12_device_destroy_vkd3d_queues(struct d3d12_device *device) + { + unsigned int i, j; +@@ -2612,6 +2619,9 @@ static void d3d12_device_destroy_vkd3d_queues(struct d3d12_device *device) + vkd3d_queue_destroy(queue_family->queues[j], device); + } + ++ if (queue_family->out_of_band_queue) ++ vkd3d_queue_destroy(queue_family->out_of_band_queue, device); ++ + vkd3d_free(queue_family->queues); + vkd3d_free(queue_family); + } +@@ -2652,6 +2662,12 @@ static HRESULT d3d12_device_create_vkd3d_queues(struct d3d12_device *device, + + info->queue_count = queue_info->vk_queue_create_info[k++].queueCount; + ++ /* Unless the queue family only has a single queue to allocate, when NV_low_latency2 ++ * is enabled one queue is reserved for out of band work */ ++ if (device->vk_info.NV_low_latency2 && vkd3d_queue_family_needs_out_of_band_queue(i) && ++ queue_info->vk_properties[i].queueCount > 1) ++ info->queue_count--; ++ + if (!(info->queues = vkd3d_calloc(info->queue_count, sizeof(*info->queues)))) + { + hr = E_OUTOFMEMORY; +@@ -2665,6 +2681,19 @@ static HRESULT d3d12_device_create_vkd3d_queues(struct d3d12_device *device, + goto out_destroy_queues; + } + ++ if (device->vk_info.NV_low_latency2 && vkd3d_queue_family_needs_out_of_band_queue(i) && ++ queue_info->vk_properties[i].queueCount > 1) ++ { ++ /* The low latency out of band queue is always the last queue for the family */ ++ if (FAILED((hr = vkd3d_queue_create(device, queue_info->family_index[i], ++ info->queue_count, &queue_info->vk_properties[i], &info->out_of_band_queue)))) ++ goto out_destroy_queues; ++ ++ vkd3d_set_queue_out_of_band(device, info->out_of_band_queue); ++ } ++ else ++ WARN("Could not allocate an out of band queue for queue family %u. All out of band work will happen on the in band queue.\n", i); ++ + info->vk_family_index = queue_info->family_index[i]; + info->vk_queue_flags = queue_info->vk_properties[i].queueFlags; + info->timestamp_bits = queue_info->vk_properties[i].timestampValidBits; +@@ -2684,7 +2713,11 @@ static HRESULT d3d12_device_create_vkd3d_queues(struct d3d12_device *device, + } + + #define VKD3D_MAX_QUEUE_COUNT_PER_FAMILY (4u) +-static float queue_priorities[] = {1.0f, 1.0f, 1.0f, 1.0f}; ++ ++/* The queue priorities list contains VKD3D_MAX_QUEUE_COUNT_PER_FAMILY + 1 priorities ++ * because it is possible for low latency to add an additional queue for out of band work ++ * submission. */ ++static float queue_priorities[] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; + + static uint32_t vkd3d_find_queue(unsigned int count, const VkQueueFamilyProperties *properties, + VkQueueFlags mask, VkQueueFlags flags) +@@ -2700,10 +2733,10 @@ static uint32_t vkd3d_find_queue(unsigned int count, const VkQueueFamilyProperti + return VK_QUEUE_FAMILY_IGNORED; + } + +-static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance, ++static HRESULT vkd3d_select_queues(const struct d3d12_device *device, + VkPhysicalDevice physical_device, struct vkd3d_device_queue_info *info) + { +- const struct vkd3d_vk_instance_procs *vk_procs = &vkd3d_instance->vk_procs; ++ const struct vkd3d_vk_instance_procs *vk_procs = &device->vkd3d_instance->vk_procs; + VkQueueFamilyProperties *queue_properties = NULL; + VkDeviceQueueCreateInfo *queue_info = NULL; + bool duplicate, single_queue; +@@ -2766,6 +2799,10 @@ static HRESULT vkd3d_select_queues(const struct vkd3d_instance *vkd3d_instance, + + if (single_queue) + queue_info->queueCount = 1; ++ ++ if (device->vk_info.NV_low_latency2 && vkd3d_queue_family_needs_out_of_band_queue(i) && ++ queue_info->queueCount < info->vk_properties[i].queueCount) ++ queue_info->queueCount++; + } + + vkd3d_free(queue_properties); +@@ -2808,9 +2845,6 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device, + VK_CALL(vkGetPhysicalDeviceProperties(device->vk_physical_device, &device_properties)); + device->api_version = min(device_properties.apiVersion, VKD3D_MAX_API_VERSION); + +- if (FAILED(hr = vkd3d_select_queues(device->vkd3d_instance, physical_device, &device_queue_info))) +- return hr; +- + TRACE("Using queue family %u for direct command queues.\n", + device_queue_info.family_index[VKD3D_QUEUE_FAMILY_GRAPHICS]); + TRACE("Using queue family %u for compute command queues.\n", +@@ -2857,6 +2891,13 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device, + return E_OUTOFMEMORY; + } + ++ if (FAILED(hr = vkd3d_select_queues(device, physical_device, &device_queue_info))) ++ { ++ vkd3d_free(user_extension_supported); ++ vkd3d_free(extensions); ++ return hr; ++ } ++ + /* Create device */ + device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_info.pNext = device->device_info.features2.pNext; +@@ -3285,8 +3326,9 @@ void d3d12_device_return_query_pool(struct d3d12_device *device, const struct vk } /* ID3D12Device */ @@ -409,7 +550,7 @@ index c7a1054f..6fe95d48 100644 HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(d3d12_device_iface *iface, REFIID riid, void **object) -@@ -3242,6 +3244,14 @@ HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(d3d12_device_iface *iface, +@@ -3333,6 +3375,14 @@ HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(d3d12_device_iface *iface, return S_OK; } @@ -424,7 +565,7 @@ index c7a1054f..6fe95d48 100644 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); *object = NULL; -@@ -8188,6 +8198,7 @@ static void d3d12_device_replace_vtable(struct d3d12_device *device) +@@ -8349,6 +8399,7 @@ static void d3d12_device_replace_vtable(struct d3d12_device *device) extern CONST_VTBL struct ID3D12DeviceExtVtbl d3d12_device_vkd3d_ext_vtbl; extern CONST_VTBL struct ID3D12DXVKInteropDeviceVtbl d3d12_dxvk_interop_device_vtbl; @@ -432,8 +573,12 @@ index c7a1054f..6fe95d48 100644 static void vkd3d_scratch_pool_init(struct d3d12_device *device) { -@@ -8258,6 +8269,7 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, +@@ -8417,8 +8468,11 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, + goto out_free_mutex; + } ++ spinlock_init(&device->low_latency_swapchain_spinlock); ++ device->ID3D12DeviceExt_iface.lpVtbl = &d3d12_device_vkd3d_ext_vtbl; device->ID3D12DXVKInteropDevice_iface.lpVtbl = &d3d12_dxvk_interop_device_vtbl; + device->ID3DLowLatencyDevice_iface.lpVtbl = &d3d_low_latency_device_vtbl; @@ -441,7 +586,7 @@ index c7a1054f..6fe95d48 100644 if ((rc = rwlock_init(&device->vertex_input_lock))) { diff --git a/libs/vkd3d/device_vkd3d_ext.c b/libs/vkd3d/device_vkd3d_ext.c -index 5bb7eca8..cf102474 100644 +index 5bb7eca840..4cd9b5c419 100644 --- a/libs/vkd3d/device_vkd3d_ext.c +++ b/libs/vkd3d/device_vkd3d_ext.c @@ -20,18 +20,18 @@ @@ -548,7 +693,7 @@ index 5bb7eca8..cf102474 100644 { if (!uav_info) return E_INVALIDARG; -@@ -417,3 +420,136 @@ CONST_VTBL struct ID3D12DXVKInteropDeviceVtbl d3d12_dxvk_interop_device_vtbl = +@@ -417,3 +420,138 @@ CONST_VTBL struct ID3D12DXVKInteropDeviceVtbl d3d12_dxvk_interop_device_vtbl = d3d12_dxvk_interop_device_LockCommandQueue, d3d12_dxvk_interop_device_UnlockCommandQueue, }; @@ -600,7 +745,7 @@ index 5bb7eca8..cf102474 100644 + return E_NOTIMPL; + + if (device->swapchain_info.low_latency_swapchain) -+ return dxgi_vk_swap_chain_latency_sleep(device->swapchain_info.low_latency_swapchain); ++ dxgi_vk_swap_chain_latency_sleep(device->swapchain_info.low_latency_swapchain); + + return S_OK; +} @@ -616,7 +761,7 @@ index 5bb7eca8..cf102474 100644 + return E_NOTIMPL; + + if (device->swapchain_info.low_latency_swapchain) -+ return dxgi_vk_swap_chain_set_latency_sleep_mode(device->swapchain_info.low_latency_swapchain, low_latency_mode, low_latency_boost, minimum_interval_us); ++ dxgi_vk_swap_chain_set_latency_sleep_mode(device->swapchain_info.low_latency_swapchain, low_latency_mode, low_latency_boost, minimum_interval_us); + + return S_OK; +} @@ -633,8 +778,8 @@ index 5bb7eca8..cf102474 100644 + if (!device->vk_info.NV_low_latency2) + return E_NOTIMPL; + -+ // Offset the frameID by one to ensure it will always -+ // be a valid presentID ++ /* Offset the frameID by one to ensure it will always ++ * be a valid presentID */ + internal_frame_id = frameID + 1; + + switch (vk_marker) @@ -648,10 +793,12 @@ index 5bb7eca8..cf102474 100644 + case VK_LATENCY_MARKER_PRESENT_START_NV: + device->frame_markers.present = internal_frame_id; + break; ++ default: ++ break; + } + + if (device->swapchain_info.low_latency_swapchain) -+ return dxgi_vk_swap_chain_set_latency_marker(device->swapchain_info.low_latency_swapchain, internal_frame_id, vk_marker); ++ dxgi_vk_swap_chain_set_latency_marker(device->swapchain_info.low_latency_swapchain, internal_frame_id, vk_marker); + + return S_OK; +} @@ -666,7 +813,7 @@ index 5bb7eca8..cf102474 100644 + return E_NOTIMPL; + + if (device->swapchain_info.low_latency_swapchain) -+ return dxgi_vk_swap_chain_get_latency_info(device->swapchain_info.low_latency_swapchain, latency_results); ++ dxgi_vk_swap_chain_get_latency_info(device->swapchain_info.low_latency_swapchain, latency_results); + + return S_OK; +} @@ -686,10 +833,10 @@ index 5bb7eca8..cf102474 100644 + d3d12_low_latency_device_GetLatencyInfo +}; diff --git a/libs/vkd3d/meson.build b/libs/vkd3d/meson.build -index 54955a89..3b551ce0 100644 +index 04394fd9f9..9c91ffcd27 100644 --- a/libs/vkd3d/meson.build +++ b/libs/vkd3d/meson.build -@@ -48,6 +48,7 @@ vkd3d_src = [ +@@ -60,6 +60,7 @@ vkd3d_src = [ 'cache.c', 'command.c', 'command_list_vkd3d_ext.c', @@ -698,20 +845,12 @@ index 54955a89..3b551ce0 100644 'device_vkd3d_ext.c', 'heap.c', diff --git a/libs/vkd3d/swapchain.c b/libs/vkd3d/swapchain.c -index 99174040..627a3514 100644 +index d0bc526d4a..3ee58d9e51 100644 --- a/libs/vkd3d/swapchain.c +++ b/libs/vkd3d/swapchain.c -@@ -58,6 +58,7 @@ struct dxgi_vk_swap_chain_present_request - DXGI_COLOR_SPACE_TYPE dxgi_color_space_type; - DXGI_VK_HDR_METADATA dxgi_hdr_metadata; - uint32_t swap_interval; -+ uint64_t frame_id; - bool modifies_hdr_metadata; - }; - -@@ -67,6 +68,13 @@ struct present_wait_entry - uint64_t begin_frame_time_ns; - }; +@@ -49,6 +49,13 @@ static HRESULT STDMETHODCALLTYPE dxgi_vk_swap_chain_factory_QueryInterface(IDXGI + return ID3D12CommandQueue_QueryInterface(&chain->queue->ID3D12CommandQueue_iface, riid, object); + } +struct low_latency_state +{ @@ -720,58 +859,170 @@ index 99174040..627a3514 100644 + uint32_t minimum_interval_us; +}; + - struct dxgi_vk_swap_chain + struct dxgi_vk_swap_chain_present_request { - IDXGIVkSwapChain IDXGIVkSwapChain_iface; -@@ -133,6 +141,16 @@ struct dxgi_vk_swap_chain - /* State tracking in present tasks on how to deal with swapchain recreation. */ - bool force_swapchain_recreation; - bool is_surface_lost; + uint64_t begin_frame_time_ns; +@@ -58,6 +65,9 @@ struct dxgi_vk_swap_chain_present_request + DXGI_COLOR_SPACE_TYPE dxgi_color_space_type; + DXGI_VK_HDR_METADATA dxgi_hdr_metadata; + uint32_t swap_interval; ++ uint64_t frame_id; ++ struct low_latency_state requested_low_latency_state; ++ bool low_latency_update_requested; + bool modifies_hdr_metadata; + }; + +@@ -73,6 +83,7 @@ struct dxgi_vk_swap_chain + struct d3d12_command_queue *queue; + + LONG refcount; ++ LONG internal_refcount; + DXGI_SWAP_CHAIN_DESC1 desc; + + vkd3d_native_sync_handle frame_latency_event; +@@ -85,6 +96,9 @@ struct dxgi_vk_swap_chain + bool frame_latency_internal_is_static; + VkSurfaceKHR vk_surface; + ++ struct low_latency_state requested_low_latency_state; ++ bool low_latency_update_requested; ++ + bool debug_latency; + bool swapchain_maintenance1; + +@@ -146,6 +160,21 @@ struct dxgi_vk_swap_chain + VkPresentModeKHR unlocked_present_mode; + bool compatible_unlocked_present_mode; + bool present_mode_forces_fifo; + + /* Info about the current low latency state of the swapchain */ -+ pthread_mutex_t low_latency_lock; ++ uint32_t low_latency_present_mode_count; ++ VkPresentModeKHR low_latency_present_modes[16]; ++ ++ pthread_mutex_t low_latency_swapchain_lock; ++ pthread_mutex_t low_latency_state_update_lock; + + VkSemaphore low_latency_sem; + uint64_t low_latency_sem_value; -+ -+ bool low_latency_update_requested; -+ struct low_latency_state requested_low_latency_state; ++ ++ uint64_t previous_application_frame_id; ++ bool using_application_frame_id; ++ + struct low_latency_state low_latency_state; } present; struct dxgi_vk_swap_chain_present_request request, request_ring[DXGI_MAX_SWAP_CHAIN_BUFFERS]; -@@ -317,6 +335,13 @@ static ULONG STDMETHODCALLTYPE dxgi_vk_swap_chain_Release(IDXGIVkSwapChain *ifac +@@ -390,6 +419,13 @@ static void dxgi_vk_swap_chain_cleanup(struct dxgi_vk_swap_chain *chain) + for (i = 0; i < ARRAY_SIZE(chain->present.vk_swapchain_fences); i++) + VK_CALL(vkDestroyFence(chain->queue->device->vk_device, chain->present.vk_swapchain_fences[i], NULL)); + ++ if (chain->queue->device->vk_info.NV_low_latency2) ++ { ++ VK_CALL(vkDestroySemaphore(chain->queue->device->vk_device, chain->present.low_latency_sem, NULL)); ++ pthread_mutex_destroy(&chain->present.low_latency_swapchain_lock); ++ pthread_mutex_destroy(&chain->present.low_latency_state_update_lock); ++ } ++ + VK_CALL(vkDestroySwapchainKHR(chain->queue->device->vk_device, chain->present.vk_swapchain, NULL)); + + for (i = 0; i < ARRAY_SIZE(chain->user.backbuffers); i++) +@@ -414,14 +450,18 @@ static ULONG STDMETHODCALLTYPE dxgi_vk_swap_chain_AddRef(IDXGIVkSwapChain *iface + { + struct dxgi_vk_swap_chain *chain = impl_from_IDXGIVkSwapChain(iface); + UINT refcount = InterlockedIncrement(&chain->refcount); ++ + TRACE("iface %p, refcount %u\n", iface, refcount); ++ ++ if (refcount == 1) ++ dxgi_vk_swap_chain_incref(chain); ++ + return refcount; + } + + static ULONG STDMETHODCALLTYPE dxgi_vk_swap_chain_Release(IDXGIVkSwapChain *iface) + { + struct dxgi_vk_swap_chain *chain = impl_from_IDXGIVkSwapChain(iface); +- struct d3d12_command_queue *queue = chain->queue; + UINT refcount; + + refcount = InterlockedDecrement(&chain->refcount); +@@ -429,11 +469,16 @@ static ULONG STDMETHODCALLTYPE dxgi_vk_swap_chain_Release(IDXGIVkSwapChain *ifac if (!refcount) { ++ /* Calling this from the submission thread will result in a deadlock, so ++ * drain the swapchain queue now. */ + dxgi_vk_swap_chain_drain_queue(chain); +- dxgi_vk_swap_chain_cleanup(chain); +- vkd3d_free(chain); +- ID3D12CommandQueue_Release(&queue->ID3D12CommandQueue_iface); ++ + if (chain->queue->device->vk_info.NV_low_latency2) -+ { -+ pthread_mutex_lock(&chain->present.low_latency_lock); + d3d12_device_remove_swapchain(chain->queue->device, chain); -+ pthread_mutex_unlock(&chain->present.low_latency_lock); -+ } + - dxgi_vk_swap_chain_drain_queue(chain); - dxgi_vk_swap_chain_cleanup(chain); - vkd3d_free(chain); -@@ -760,6 +785,7 @@ static HRESULT STDMETHODCALLTYPE dxgi_vk_swap_chain_Present(IDXGIVkSwapChain *if ++ dxgi_vk_swap_chain_decref(chain); + } ++ + return refcount; + } + +@@ -873,8 +918,23 @@ static HRESULT STDMETHODCALLTYPE dxgi_vk_swap_chain_Present(IDXGIVkSwapChain *if request->dxgi_hdr_metadata = chain->user.dxgi_hdr_metadata; request->modifies_hdr_metadata = chain->user.modifies_hdr_metadata; request->begin_frame_time_ns = chain->user.begin_frame_time_ns; + request->frame_id = chain->queue->device->frame_markers.present; chain->user.modifies_hdr_metadata = false; ++ if (chain->queue->device->vk_info.NV_low_latency2 && chain->low_latency_update_requested) ++ { ++ pthread_mutex_lock(&chain->present.low_latency_state_update_lock); ++ request->requested_low_latency_state = chain->requested_low_latency_state; ++ request->low_latency_update_requested = true; ++ chain->low_latency_update_requested = false; ++ pthread_mutex_unlock(&chain->present.low_latency_state_update_lock); ++ } ++ else ++ { ++ memset(&request->requested_low_latency_state, 0, sizeof(request->requested_low_latency_state)); ++ request->low_latency_update_requested = false; ++ } ++ /* Need to process this task in queue thread to deal with wait-before-signal. -@@ -1283,6 +1309,8 @@ static void dxgi_vk_swap_chain_recreate_swapchain_in_present_task(struct dxgi_vk - VkDevice vk_device = chain->queue->device->vk_device; - VkCommandPoolCreateInfo command_pool_create_info; - VkSwapchainCreateInfoKHR swapchain_create_info; + * All interesting works happens in the callback. */ + chain->user.blit_count += 1; +@@ -1236,6 +1296,12 @@ static void dxgi_vk_swap_chain_destroy_swapchain_in_present_task(struct dxgi_vk_ + if (!chain->present.vk_swapchain) + return; + ++ /* If we are going to destroy the swapchain and the device supports VK_NV_low_latency2 ++ * take the low latency lock. This ensures none of the other NV low latency functions ++ * will attempt to use the stale swapchain handle. */ ++ if (chain->queue->device->vk_info.NV_low_latency2) ++ pthread_mutex_lock(&chain->present.low_latency_swapchain_lock); ++ + if (chain->swapchain_maintenance1) + { + dxgi_vk_swap_chain_drain_swapchain_fences(chain); +@@ -1268,6 +1334,9 @@ static void dxgi_vk_swap_chain_destroy_swapchain_in_present_task(struct dxgi_vk_ + chain->present.present_id_valid = false; + chain->present.present_id = 0; + chain->present.current_backbuffer_index = UINT32_MAX; ++ ++ if (chain->queue->device->vk_info.NV_low_latency2) ++ pthread_mutex_unlock(&chain->present.low_latency_swapchain_lock); + } + + static VkColorSpaceKHR convert_color_space(DXGI_COLOR_SPACE_TYPE dxgi_color_space) +@@ -1452,6 +1521,8 @@ static void dxgi_vk_swap_chain_recreate_swapchain_in_present_task(struct dxgi_vk + { + const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; + VkPhysicalDevice vk_physical_device = chain->queue->device->vk_physical_device; + VkSwapchainLatencyCreateInfoNV swapchain_latency_create_info; + VkLatencySleepModeInfoNV swapchain_latency_sleep_mode_info; - VkSurfaceCapabilitiesKHR surface_caps; - VkSurfaceFormatKHR surface_format; - VkImageViewCreateInfo view_info; -@@ -1374,6 +1402,15 @@ static void dxgi_vk_swap_chain_recreate_swapchain_in_present_task(struct dxgi_vk + VkSwapchainPresentModesCreateInfoEXT present_modes_info; + VkDevice vk_device = chain->queue->device->vk_device; + VkCommandPoolCreateInfo command_pool_create_info; +@@ -1573,6 +1644,15 @@ static void dxgi_vk_swap_chain_recreate_swapchain_in_present_task(struct dxgi_vk swapchain_create_info.imageExtent.height = max(swapchain_create_info.imageExtent.height, surface_caps.minImageExtent.height); swapchain_create_info.imageExtent.height = min(swapchain_create_info.imageExtent.height, surface_caps.maxImageExtent.height); @@ -787,15 +1038,15 @@ index 99174040..627a3514 100644 vr = VK_CALL(vkCreateSwapchainKHR(vk_device, &swapchain_create_info, NULL, &chain->present.vk_swapchain)); if (vr < 0) { -@@ -1387,6 +1424,29 @@ static void dxgi_vk_swap_chain_recreate_swapchain_in_present_task(struct dxgi_vk +@@ -1586,6 +1666,30 @@ static void dxgi_vk_swap_chain_recreate_swapchain_in_present_task(struct dxgi_vk INFO("Got %u swapchain images.\n", chain->present.backbuffer_count); + /* If low latency is supported restore the current low latency state now */ + if (chain->queue->device->vk_info.NV_low_latency2) + { -+ struct low_latency_state* low_latency_state = chain->present.low_latency_update_requested ? -+ &chain->present.requested_low_latency_state : &chain->present.low_latency_state; ++ struct low_latency_state* low_latency_state = chain->request.low_latency_update_requested ? ++ &chain->request.requested_low_latency_state : &chain->present.low_latency_state; + + memset(&swapchain_latency_sleep_mode_info, 0, sizeof(swapchain_latency_sleep_mode_info)); + swapchain_latency_sleep_mode_info.sType = VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV; @@ -807,70 +1058,136 @@ index 99174040..627a3514 100644 + + VK_CALL(vkSetLatencySleepModeNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &swapchain_latency_sleep_mode_info)); + -+ if (chain->present.low_latency_update_requested) -+ { -+ memcpy(&chain->present.low_latency_state, &chain->present.requested_low_latency_state, sizeof(struct low_latency_state)); -+ chain->present.low_latency_update_requested = false; -+ } ++ /* If low latency is enabled assume the application will start driving the frame id again. */ ++ chain->present.using_application_frame_id = low_latency_state->mode; ++ chain->present.previous_application_frame_id = 0; ++ ++ if (chain->request.low_latency_update_requested) ++ chain->present.low_latency_state = chain->request.requested_low_latency_state; + } + memset(&view_info, 0, sizeof(view_info)); view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_info.format = swapchain_create_info.imageFormat; -@@ -1795,9 +1855,12 @@ static void dxgi_vk_swap_chain_present_iteration(struct dxgi_vk_swap_chain *chai +@@ -1626,6 +1730,10 @@ static bool dxgi_vk_swap_chain_request_needs_swapchain_recreation( + return request->dxgi_color_space_type != last_request->dxgi_color_space_type || + request->dxgi_format != last_request->dxgi_format || + request->target_min_image_count != last_request->target_min_image_count || ++ request->low_latency_update_requested || ++ (chain->present.low_latency_state.mode && ++ (request->frame_id != chain->present.previous_application_frame_id) && ++ !chain->present.using_application_frame_id) || + ((!!request->swap_interval) != (!!last_request->swap_interval) && + !chain->present.compatible_unlocked_present_mode); + } +@@ -2019,6 +2127,7 @@ static void dxgi_vk_swap_chain_present_iteration(struct dxgi_vk_swap_chain *chai + const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; + VkSwapchainPresentFenceInfoEXT present_fence_info; + VkSwapchainPresentModeInfoEXT present_mode_info; ++ uint32_t max_present_iterations; + VkPresentModeKHR present_mode; + VkPresentInfoKHR present_info; + VkPresentIdKHR present_id; +@@ -2035,6 +2144,12 @@ static void dxgi_vk_swap_chain_present_iteration(struct dxgi_vk_swap_chain *chai + if (!chain->present.vk_swapchain) + return; + ++ /* If low latency is enabled we should only try to present once to avoid having to ++ * increment the present id for each failed present. Make sure to do this after checking ++ * if the swapchain needs to be recreated so the low latency state is up to date. */ ++ max_present_iterations = chain->present.low_latency_state.mode ? ++ 0 : 3; ++ + vr = dxgi_vk_swap_chain_try_acquire_next_image(chain); + VKD3D_DEVICE_REPORT_FAULT_AND_BREADCRUMB_IF(chain->queue->device, vr == VK_ERROR_DEVICE_LOST); + +@@ -2046,7 +2161,7 @@ static void dxgi_vk_swap_chain_present_iteration(struct dxgi_vk_swap_chain *chai + + if (vr == VK_ERROR_OUT_OF_DATE_KHR) + { +- if (retry_counter < 3) ++ if (retry_counter < max_present_iterations) + dxgi_vk_swap_chain_present_iteration(chain, retry_counter + 1); + } + else if (vr == VK_ERROR_SURFACE_LOST_KHR) +@@ -2081,11 +2196,28 @@ static void dxgi_vk_swap_chain_present_iteration(struct dxgi_vk_swap_chain *chai * Non-FIFO swapchains will pump their frame latency handles through the fallback path of blit command being done. * Especially on Xwayland, the present ID is updated when images actually hit on-screen due to MAILBOX behavior. * This would unnecessarily stall our progress. */ -- if (chain->wait_thread.active && !chain->present.present_id_valid && chain->request.swap_interval > 0) +- if (chain->wait_thread.active && !chain->present.present_id_valid && swapchain_is_fifo) + if (chain->wait_thread.active && !chain->present.present_id_valid && -+ (chain->request.swap_interval > 0 || chain->present.low_latency_state.mode)) ++ (swapchain_is_fifo || chain->present.low_latency_state.mode)) { -- chain->present.present_id += 1; -+ chain->present.present_id = (chain->present.low_latency_state.mode) ? -+ chain->request.frame_id : chain->present.present_id + 1; +- /* If we recreate swapchain, we still want to maintain a monotonically increasing counter here for +- * profiling purposes. */ +- chain->present.present_id = chain->present.complete_count + 1; ++ if (chain->present.low_latency_state.mode && ++ chain->request.frame_id > chain->present.previous_application_frame_id) ++ { ++ chain->present.present_id = chain->request.frame_id; ++ chain->present.previous_application_frame_id = chain->request.frame_id; ++ } ++ else ++ { ++ /* If we recreate swapchain, we still want to maintain a monotonically increasing counter here for ++ * profiling purposes. */ ++ chain->present.present_id = chain->present.low_latency_state.mode ? ++ chain->present.present_id + 1 : chain->present.complete_count + 1; ++ ++ /* It is possible for an application to stop providing low latency frame ids. If that happens we are ++ * now responsible for ensuring the present id is always incrementing. If the application starts to ++ * provide them again, we will have to recreate the swapchain. */ ++ chain->present.using_application_frame_id = false; ++ } + present_id.sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR; present_id.pNext = NULL; present_id.swapchainCount = 1; -@@ -1905,6 +1968,9 @@ static void dxgi_vk_swap_chain_present_callback(void *chain_) - if (!chain->wait_thread.active) - present_count = 1; +@@ -2150,7 +2282,7 @@ static void dxgi_vk_swap_chain_present_iteration(struct dxgi_vk_swap_chain *chai -+ if (chain->queue->device->vk_info.NV_low_latency2) -+ pthread_mutex_lock(&chain->present.low_latency_lock); -+ - for (i = 0; i < present_count; i++) + if (vr == VK_ERROR_OUT_OF_DATE_KHR) { - /* A present iteration may or may not render to backbuffer. We'll apply best effort here. -@@ -1912,6 +1978,9 @@ static void dxgi_vk_swap_chain_present_callback(void *chain_) - dxgi_vk_swap_chain_present_iteration(chain, 0); +- if (retry_counter < 3) ++ if (retry_counter < max_present_iterations) + dxgi_vk_swap_chain_present_iteration(chain, retry_counter + 1); } + else if (vr == VK_ERROR_SURFACE_LOST_KHR) +@@ -2222,8 +2354,10 @@ static void dxgi_vk_swap_chain_present_callback(void *chain_) + * TODO: Propose VK_EXT_present_interval. */ + present_count = max(1u, chain->request.swap_interval); -+ if (chain->queue->device->vk_info.NV_low_latency2) -+ pthread_mutex_unlock(&chain->present.low_latency_lock); -+ - /* When this is signalled, lets main thread know that it's safe to free user buffers. - * Signal this just once on the outside since we might have retries, swap_interval > 1, etc, which complicates command buffer recycling. */ - dxgi_vk_swap_chain_present_signal_blit_semaphore(chain); -@@ -2045,6 +2114,52 @@ static HRESULT dxgi_vk_swap_chain_init_waiter_thread(struct dxgi_vk_swap_chain * +- /* If we hit the legacy way of synchronizing with swapchain, blitting multiple times would be horrible. */ +- if (!chain->wait_thread.active) ++ /* If we hit the legacy way of synchronizing with swapchain, blitting multiple times would be horrible. ++ * Also if low latency mode is enabled only do a single present iteration to avoid falling off the application ++ * provided frame id path. */ ++ if (!chain->wait_thread.active || chain->present.low_latency_state.mode) + present_count = 1; + + for (i = 0; i < present_count; i++) +@@ -2374,6 +2508,80 @@ static HRESULT dxgi_vk_swap_chain_init_waiter_thread(struct dxgi_vk_swap_chain * return S_OK; } +static HRESULT dxgi_vk_swap_chain_init_low_latency(struct dxgi_vk_swap_chain* chain) +{ + const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; ++ VkPhysicalDevice vk_physical_device = chain->queue->device->vk_physical_device; + ++ VkLatencySurfaceCapabilitiesNV latency_surface_caps; + VkSemaphoreTypeCreateInfoKHR semaphore_type_info; ++ VkPhysicalDeviceSurfaceInfo2KHR surface_info; ++ VkSurfaceCapabilities2KHR surface_caps; + VkSemaphoreCreateInfo semaphore_info; + VkResult vr; + ++ chain->present.low_latency_present_mode_count = 0; ++ + chain->present.low_latency_sem = VK_NULL_HANDLE; + chain->present.low_latency_sem_value = 0; + -+ chain->present.low_latency_update_requested = false; -+ chain->present.requested_low_latency_state.mode = false; -+ chain->present.requested_low_latency_state.boost = false; -+ chain->present.requested_low_latency_state.minimum_interval_us = 0; ++ chain->present.previous_application_frame_id = 0; ++ chain->present.using_application_frame_id = false; + + chain->present.low_latency_state.mode = false; + chain->present.low_latency_state.boost = false; @@ -878,6 +1195,29 @@ index 99174040..627a3514 100644 + + if (chain->queue->device->vk_info.NV_low_latency2) + { ++ memset(&surface_info, 0, sizeof(surface_info)); ++ surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR; ++ surface_info.pNext = NULL; ++ surface_info.surface = chain->vk_surface; ++ ++ memset(&latency_surface_caps, 0, sizeof(latency_surface_caps)); ++ latency_surface_caps.sType = VK_STRUCTURE_TYPE_LATENCY_SURFACE_CAPABILITIES_NV; ++ latency_surface_caps.presentModeCount = ARRAY_SIZE(chain->present.low_latency_present_modes); ++ latency_surface_caps.pPresentModes = chain->present.low_latency_present_modes; ++ ++ memset(&surface_caps, 0, sizeof(surface_caps)); ++ surface_caps.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR; ++ surface_caps.pNext = &latency_surface_caps; ++ ++ if ((vr = VK_CALL(vkGetPhysicalDeviceSurfaceCapabilities2KHR(vk_physical_device, &surface_info, ++ &surface_caps))) < 0) ++ { ++ ERR("Failed to query latency surface capabilities count, vr %d.\n", vr); ++ return hresult_from_vk_result(vr); ++ } ++ ++ chain->present.low_latency_present_mode_count = latency_surface_caps.presentModeCount; ++ + memset(&semaphore_type_info, 0, sizeof(semaphore_type_info)); + semaphore_type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR; + semaphore_type_info.pNext = NULL; @@ -889,14 +1229,15 @@ index 99174040..627a3514 100644 + semaphore_info.pNext = &semaphore_type_info; + semaphore_info.flags = 0; + -+ if ((vr = VK_CALL(vkCreateSemaphore(chain->queue->device->vk_device, -+ &semaphore_info, NULL, &chain->present.low_latency_sem))) < 0) ++ if ((vr = VK_CALL(vkCreateSemaphore(chain->queue->device->vk_device, &semaphore_info, ++ NULL, &chain->present.low_latency_sem))) < 0) + { + ERR("Failed to create semaphore, vr %d.\n", vr); + return hresult_from_vk_result(vr); + } + -+ pthread_mutex_init(&chain->present.low_latency_lock, NULL); ++ pthread_mutex_init(&chain->present.low_latency_swapchain_lock, NULL); ++ pthread_mutex_init(&chain->present.low_latency_state_update_lock, NULL); + } + + return S_OK; @@ -905,7 +1246,15 @@ index 99174040..627a3514 100644 static HRESULT dxgi_vk_swap_chain_init(struct dxgi_vk_swap_chain *chain, IDXGIVkSurfaceFactory *pFactory, const DXGI_SWAP_CHAIN_DESC1 *pDesc, struct d3d12_command_queue *queue) { -@@ -2070,6 +2185,9 @@ static HRESULT dxgi_vk_swap_chain_init(struct dxgi_vk_swap_chain *chain, IDXGIVk +@@ -2381,6 +2589,7 @@ static HRESULT dxgi_vk_swap_chain_init(struct dxgi_vk_swap_chain *chain, IDXGIVk + + chain->IDXGIVkSwapChain_iface.lpVtbl = &dxgi_vk_swap_chain_vtbl; + chain->refcount = 1; ++ chain->internal_refcount = 1; + chain->queue = queue; + chain->desc = *pDesc; + +@@ -2402,6 +2611,9 @@ static HRESULT dxgi_vk_swap_chain_init(struct dxgi_vk_swap_chain *chain, IDXGIVk if (FAILED(hr = dxgi_vk_swap_chain_init_waiter_thread(chain))) goto err; @@ -915,21 +1264,17 @@ index 99174040..627a3514 100644 ID3D12CommandQueue_AddRef(&queue->ID3D12CommandQueue_iface); return S_OK; -@@ -2097,6 +2215,13 @@ static HRESULT STDMETHODCALLTYPE dxgi_vk_swap_chain_factory_CreateSwapChain(IDXG +@@ -2429,6 +2641,9 @@ static HRESULT STDMETHODCALLTYPE dxgi_vk_swap_chain_factory_CreateSwapChain(IDXG return hr; } + if (chain->queue->device->vk_info.NV_low_latency2) -+ { -+ pthread_mutex_lock(&chain->present.low_latency_lock); + d3d12_device_register_swapchain(chain->queue->device, chain); -+ pthread_mutex_unlock(&chain->present.low_latency_lock); -+ } + *ppSwapchain = &chain->IDXGIVkSwapChain_iface; return S_OK; } -@@ -2112,6 +2237,192 @@ static CONST_VTBL struct IDXGIVkSwapChainFactoryVtbl dxgi_vk_swap_chain_factory_ +@@ -2444,6 +2659,192 @@ static CONST_VTBL struct IDXGIVkSwapChainFactoryVtbl dxgi_vk_swap_chain_factory_ dxgi_vk_swap_chain_factory_CreateSwapChain, }; @@ -938,28 +1283,34 @@ index 99174040..627a3514 100644 + return chain->present.low_latency_state.mode; +} + -+HRESULT dxgi_vk_swap_chain_latency_sleep(struct dxgi_vk_swap_chain* chain) ++void dxgi_vk_swap_chain_latency_sleep(struct dxgi_vk_swap_chain* chain) +{ + const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; -+ + VkLatencySleepInfoNV latency_sleep_info; + VkSemaphoreWaitInfo sem_wait_info; ++ bool should_sleep = false; + -+ if (chain->present.low_latency_state.mode) -+ { -+ // Increment the low latency sem value before the wait -+ chain->present.low_latency_sem_value++; ++ /* Increment the low latency sem value before the wait */ ++ chain->present.low_latency_sem_value++; ++ ++ memset(&latency_sleep_info, 0, sizeof(latency_sleep_info)); ++ latency_sleep_info.sType = VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV; ++ latency_sleep_info.pNext = NULL; ++ latency_sleep_info.signalSemaphore = chain->present.low_latency_sem; ++ latency_sleep_info.value = chain->present.low_latency_sem_value; + -+ memset(&latency_sleep_info, 0, sizeof(latency_sleep_info)); -+ latency_sleep_info.sType = VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV; -+ latency_sleep_info.pNext = NULL; -+ latency_sleep_info.signalSemaphore = chain->present.low_latency_sem; -+ latency_sleep_info.value = chain->present.low_latency_sem_value; ++ pthread_mutex_lock(&chain->present.low_latency_swapchain_lock); + -+ pthread_mutex_lock(&chain->present.low_latency_lock); ++ if (chain->present.vk_swapchain) ++ { ++ should_sleep = true; + VK_CALL(vkLatencySleepNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &latency_sleep_info)); -+ pthread_mutex_unlock(&chain->present.low_latency_lock); ++ } + ++ pthread_mutex_unlock(&chain->present.low_latency_swapchain_lock); ++ ++ if (should_sleep) ++ { + memset(&sem_wait_info, 0, sizeof(sem_wait_info)); + sem_wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + sem_wait_info.pNext = NULL; @@ -970,160 +1321,154 @@ index 99174040..627a3514 100644 + + VK_CALL(vkWaitSemaphores(chain->queue->device->vk_device, &sem_wait_info, UINT64_MAX)); + } -+ -+ return S_OK; +} + -+HRESULT dxgi_vk_swap_chain_set_latency_sleep_mode(struct dxgi_vk_swap_chain* chain, bool low_latency_mode, ++void dxgi_vk_swap_chain_set_latency_sleep_mode(struct dxgi_vk_swap_chain* chain, bool low_latency_mode, + bool low_latency_boost, uint32_t minimum_interval_us) +{ -+ const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; -+ -+ VkLatencySleepModeInfoNV latency_sleep_mode_info; -+ -+ if (low_latency_mode == chain->present.low_latency_state.mode && -+ low_latency_boost == chain->present.low_latency_state.boost && -+ minimum_interval_us == chain->present.low_latency_state.minimum_interval_us) -+ { -+ return S_OK; -+ } -+ -+ // If we are enabling low latency mode, recreate the swapchain -+ // to sync the frameIds provided by nvapi to the presentID -+ // used a present time -+ if (low_latency_mode && !chain->present.low_latency_state.mode) -+ { -+ chain->present.requested_low_latency_state.mode = low_latency_mode; -+ chain->present.requested_low_latency_state.boost = low_latency_boost; -+ chain->present.requested_low_latency_state.minimum_interval_us = minimum_interval_us; -+ -+ // In order to use the frameId provided by the application -+ // the swapchain will have to be recreated to reset the -+ // present ID -+ chain->present.low_latency_update_requested = true; -+ chain->present.force_swapchain_recreation = true; -+ } -+ else -+ { -+ memset(&latency_sleep_mode_info, 0, sizeof(latency_sleep_mode_info)); -+ latency_sleep_mode_info.sType = VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV; -+ latency_sleep_mode_info.pNext = NULL; -+ latency_sleep_mode_info.lowLatencyMode = low_latency_mode; -+ latency_sleep_mode_info.lowLatencyBoost = low_latency_boost; -+ latency_sleep_mode_info.minimumIntervalUs = minimum_interval_us; -+ -+ pthread_mutex_lock(&chain->present.low_latency_lock); -+ VK_CALL(vkSetLatencySleepModeNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &latency_sleep_mode_info)); -+ pthread_mutex_unlock(&chain->present.low_latency_lock); -+ -+ chain->present.low_latency_state.mode = low_latency_mode; -+ chain->present.low_latency_state.boost = low_latency_boost; -+ chain->present.low_latency_state.minimum_interval_us = minimum_interval_us; -+ } -+ -+ return S_OK; ++ /* If the low latency state is already set to what the application is ++ * requesting, and there isn't an update in flight it is safe to skip ++ * this request. */ ++ if (chain->low_latency_update_requested == false && ++ low_latency_mode == chain->present.low_latency_state.mode && ++ low_latency_boost == chain->present.low_latency_state.boost && ++ minimum_interval_us == chain->present.low_latency_state.minimum_interval_us) ++ return; ++ ++ pthread_mutex_lock(&chain->present.low_latency_state_update_lock); ++ ++ chain->requested_low_latency_state.mode = low_latency_mode; ++ chain->requested_low_latency_state.boost = low_latency_boost; ++ chain->requested_low_latency_state.minimum_interval_us = minimum_interval_us; ++ ++ /* The actual call to vkSetLatencySleepModeNV will happen ++ * in the present task when the swapchain is recreated. This ++ * is required when enabling low latency mode to use the frameId ++ * provided by the application, because the id it provides may be ++ * less than the largest id already used with the current swapchain. */ ++ chain->low_latency_update_requested = true; ++ ++ pthread_mutex_unlock(&chain->present.low_latency_state_update_lock); +} + -+HRESULT dxgi_vk_swap_chain_set_latency_marker(struct dxgi_vk_swap_chain* chain, uint64_t frameID, VkLatencyMarkerNV marker) ++void dxgi_vk_swap_chain_set_latency_marker(struct dxgi_vk_swap_chain* chain, uint64_t frameID, VkLatencyMarkerNV marker) +{ + const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; -+ + VkSetLatencyMarkerInfoNV latency_marker_info; + -+ if (chain->present.low_latency_state.mode) -+ { -+ memset(&latency_marker_info, 0, sizeof(latency_marker_info)); -+ latency_marker_info.sType = VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV; -+ latency_marker_info.pNext = NULL; -+ latency_marker_info.presentID = frameID; -+ latency_marker_info.marker = marker; ++ memset(&latency_marker_info, 0, sizeof(latency_marker_info)); ++ latency_marker_info.sType = VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV; ++ latency_marker_info.pNext = NULL; ++ latency_marker_info.presentID = frameID; ++ latency_marker_info.marker = marker; + -+ pthread_mutex_lock(&chain->present.low_latency_lock); ++ pthread_mutex_lock(&chain->present.low_latency_swapchain_lock); ++ ++ if (chain->present.vk_swapchain) + VK_CALL(vkSetLatencyMarkerNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &latency_marker_info)); -+ pthread_mutex_unlock(&chain->present.low_latency_lock); -+ } + -+ return S_OK; ++ pthread_mutex_unlock(&chain->present.low_latency_swapchain_lock); +} + -+HRESULT dxgi_vk_swap_chain_get_latency_info(struct dxgi_vk_swap_chain* chain, D3D12_LATENCY_RESULTS *latency_results) ++void dxgi_vk_swap_chain_get_latency_info(struct dxgi_vk_swap_chain* chain, D3D12_LATENCY_RESULTS *latency_results) +{ + const struct vkd3d_vk_device_procs *vk_procs = &chain->queue->device->vk_procs; -+ -+ VkGetLatencyMarkerInfoNV marker_info; + VkLatencyTimingsFrameReportNV* frame_reports; -+ uint32_t report_count; ++ VkGetLatencyMarkerInfoNV marker_info; + uint32_t i; + -+ if (!chain->present.low_latency_state.mode) ++ pthread_mutex_lock(&chain->present.low_latency_swapchain_lock); ++ ++ if (chain->present.vk_swapchain) + { -+ memset(latency_results->frame_reports, 0, sizeof(latency_results->frame_reports)); -+ return S_OK; -+ } ++ memset(&marker_info, 0, sizeof(marker_info)); ++ marker_info.sType = VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV; + -+ memset(&marker_info, 0, sizeof(marker_info)); -+ marker_info.sType = VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV; ++ VK_CALL(vkGetLatencyTimingsNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &marker_info)); + -+ pthread_mutex_lock(&chain->present.low_latency_lock); ++ if (marker_info.timingCount >= 64) ++ { ++ marker_info.timingCount = 64; ++ frame_reports = vkd3d_calloc(marker_info.timingCount, sizeof(VkLatencyTimingsFrameReportNV)); ++ for (i = 0; i < marker_info.timingCount; i++) ++ frame_reports[i].sType = VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV; ++ ++ marker_info.pTimings = frame_reports; ++ ++ VK_CALL(vkGetLatencyTimingsNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &marker_info)); ++ ++ for (i = 0; i < marker_info.timingCount; i++) ++ { ++ latency_results->frame_reports[i].frameID = frame_reports[i].presentID - 1; ++ latency_results->frame_reports[i].inputSampleTime = frame_reports[i].inputSampleTimeUs; ++ latency_results->frame_reports[i].simStartTime = frame_reports[i].simStartTimeUs; ++ latency_results->frame_reports[i].simEndTime = frame_reports[i].simEndTimeUs; ++ latency_results->frame_reports[i].renderSubmitStartTime = frame_reports[i].renderSubmitStartTimeUs; ++ latency_results->frame_reports[i].renderSubmitEndTime = frame_reports[i].renderSubmitEndTimeUs; ++ latency_results->frame_reports[i].presentStartTime = frame_reports[i].presentStartTimeUs; ++ latency_results->frame_reports[i].presentEndTime = frame_reports[i].presentEndTimeUs; ++ latency_results->frame_reports[i].driverStartTime = frame_reports[i].driverStartTimeUs; ++ latency_results->frame_reports[i].driverEndTime = frame_reports[i].driverEndTimeUs; ++ latency_results->frame_reports[i].osRenderQueueStartTime = frame_reports[i].osRenderQueueStartTimeUs; ++ latency_results->frame_reports[i].osRenderQueueEndTime = frame_reports[i].osRenderQueueEndTimeUs; ++ latency_results->frame_reports[i].gpuRenderStartTime = frame_reports[i].gpuRenderStartTimeUs; ++ latency_results->frame_reports[i].gpuRenderEndTime = frame_reports[i].gpuRenderEndTimeUs; ++ latency_results->frame_reports[i].gpuActiveRenderTimeUs = ++ frame_reports[i].gpuRenderEndTimeUs - frame_reports[i].gpuRenderStartTimeUs; ++ latency_results->frame_reports[i].gpuFrameTimeUs = 0; ++ ++ if (i) ++ { ++ latency_results->frame_reports[i].gpuFrameTimeUs = ++ frame_reports[i].gpuRenderEndTimeUs - frame_reports[i - 1].gpuRenderEndTimeUs; ++ } ++ } + -+ VK_CALL(vkGetLatencyTimingsNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &report_count, &marker_info)); ++ vkd3d_free(frame_reports); ++ } ++ else ++ { ++ /* If there are less than 64 frame reports, zero out the frame report ++ * buffer returned to the app. */ ++ memset(latency_results->frame_reports, 0, sizeof(latency_results->frame_reports)); ++ } ++ } + -+ if (report_count >= 64) -+ { -+ report_count = 64; -+ frame_reports = vkd3d_calloc(report_count, sizeof(VkLatencyTimingsFrameReportNV)); -+ for (i = 0; i < report_count; i++) -+ frame_reports[i].sType = VK_STRUCTURE_TYPE_LATENCY_TIMINGS_FRAME_REPORT_NV; ++ pthread_mutex_unlock(&chain->present.low_latency_swapchain_lock); ++} + -+ marker_info.pTimings = frame_reports; ++ULONG dxgi_vk_swap_chain_incref(struct dxgi_vk_swap_chain *chain) ++{ ++ ULONG refcount = InterlockedIncrement(&chain->internal_refcount); + -+ VK_CALL(vkGetLatencyTimingsNV(chain->queue->device->vk_device, chain->present.vk_swapchain, &report_count, &marker_info)); ++ TRACE("%p increasing refcount to %u.\n", chain, refcount); + -+ for (i = 0; i < report_count; i++) -+ { -+ latency_results->frame_reports[i].frameID = frame_reports[i].presentID - 1; -+ latency_results->frame_reports[i].inputSampleTime = frame_reports[i].inputSampleTimeUs; -+ latency_results->frame_reports[i].simStartTime = frame_reports[i].simStartTimeUs; -+ latency_results->frame_reports[i].simEndTime = frame_reports[i].simEndTimeUs; -+ latency_results->frame_reports[i].renderSubmitStartTime = frame_reports[i].renderSubmitStartTimeUs; -+ latency_results->frame_reports[i].renderSubmitEndTime = frame_reports[i].renderSubmitEndTimeUs; -+ latency_results->frame_reports[i].presentStartTime = frame_reports[i].presentStartTimeUs; -+ latency_results->frame_reports[i].presentEndTime = frame_reports[i].presentEndTimeUs; -+ latency_results->frame_reports[i].driverStartTime = frame_reports[i].driverStartTimeUs; -+ latency_results->frame_reports[i].driverEndTime = frame_reports[i].driverEndTimeUs; -+ latency_results->frame_reports[i].osRenderQueueStartTime = frame_reports[i].osRenderQueueStartTimeUs; -+ latency_results->frame_reports[i].osRenderQueueEndTime = frame_reports[i].osRenderQueueEndTimeUs; -+ latency_results->frame_reports[i].gpuRenderStartTime = frame_reports[i].gpuRenderStartTimeUs; -+ latency_results->frame_reports[i].gpuRenderEndTime = frame_reports[i].gpuRenderEndTimeUs; -+ latency_results->frame_reports[i].gpuActiveRenderTimeUs = -+ frame_reports[i].gpuRenderEndTimeUs - frame_reports[i].gpuRenderStartTimeUs; -+ latency_results->frame_reports[i].gpuFrameTimeUs = 0; -+ -+ if (i) { -+ latency_results->frame_reports[i].gpuFrameTimeUs = -+ frame_reports[i].gpuRenderEndTimeUs - frame_reports[i - 1].gpuRenderEndTimeUs; -+ } -+ } ++ return refcount; ++} + -+ vkd3d_free(frame_reports); -+ } -+ else ++ULONG dxgi_vk_swap_chain_decref(struct dxgi_vk_swap_chain *chain) ++{ ++ ULONG refcount = InterlockedDecrement(&chain->internal_refcount); ++ ++ TRACE("%p decreasing refcount to %u.\n", chain, refcount); ++ ++ if (!refcount) + { -+ // If there are less than 64 frame reports, zero out the frame report -+ // buffer returned to the app. -+ memset(latency_results->frame_reports, 0, sizeof(latency_results->frame_reports)); -+ } ++ struct d3d12_command_queue *queue = chain->queue; + -+ pthread_mutex_unlock(&chain->present.low_latency_lock); ++ dxgi_vk_swap_chain_cleanup(chain); ++ vkd3d_free(chain); ++ ID3D12CommandQueue_Release(&queue->ID3D12CommandQueue_iface); ++ } + -+ return S_OK; ++ return refcount; +} + HRESULT dxgi_vk_swap_chain_factory_init(struct d3d12_command_queue *queue, struct dxgi_vk_swap_chain_factory *chain) { chain->IDXGIVkSwapChainFactory_iface.lpVtbl = &dxgi_vk_swap_chain_factory_vtbl; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h -index 124cd75a..16234e94 100644 +index 935f3dc8dc..d3d16ac5ff 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -37,6 +37,7 @@ @@ -1134,7 +1479,7 @@ index 124cd75a..16234e94 100644 #include "vkd3d_device_vkd3d_ext.h" #include "vkd3d_string.h" #include "vkd3d_file_utils.h" -@@ -169,6 +170,7 @@ struct vkd3d_vulkan_info +@@ -172,6 +173,7 @@ struct vkd3d_vulkan_info bool NV_shader_subgroup_partitioned; bool NV_memory_decompression; bool NV_device_generated_commands_compute; @@ -1142,7 +1487,15 @@ index 124cd75a..16234e94 100644 /* VALVE extensions */ bool VALVE_mutable_descriptor_type; bool VALVE_descriptor_set_host_mapping; -@@ -3012,6 +3014,7 @@ struct d3d12_command_queue_submission_execute +@@ -3029,6 +3031,7 @@ struct vkd3d_queue + VkQueue vkd3d_queue_acquire(struct vkd3d_queue *queue); + HRESULT vkd3d_queue_create(struct d3d12_device *device, uint32_t family_index, uint32_t queue_index, + const VkQueueFamilyProperties *properties, struct vkd3d_queue **queue); ++void vkd3d_set_queue_out_of_band(struct d3d12_device *device, struct vkd3d_queue *queue); + void vkd3d_queue_destroy(struct vkd3d_queue *queue, struct d3d12_device *device); + void vkd3d_queue_release(struct vkd3d_queue *queue); + void vkd3d_queue_add_wait(struct vkd3d_queue *queue, d3d12_fence_iface *waiter, +@@ -3085,6 +3088,7 @@ struct d3d12_command_queue_submission_execute struct d3d12_command_allocator **command_allocators; UINT cmd_count; UINT num_command_allocators; @@ -1150,20 +1503,23 @@ index 124cd75a..16234e94 100644 struct vkd3d_initial_transition *transitions; size_t transition_count; -@@ -3067,12 +3070,30 @@ struct dxgi_vk_swap_chain_factory +@@ -3142,12 +3146,33 @@ struct dxgi_vk_swap_chain_factory struct d3d12_command_queue *queue; }; +struct dxgi_vk_swap_chain; + -+bool dxgi_vk_swap_chain_low_latency_enabled(struct dxgi_vk_swap_chain* chain); -+HRESULT dxgi_vk_swap_chain_latency_sleep(struct dxgi_vk_swap_chain* chain); -+HRESULT dxgi_vk_swap_chain_set_latency_sleep_mode(struct dxgi_vk_swap_chain* chain, ++bool dxgi_vk_swap_chain_low_latency_enabled(struct dxgi_vk_swap_chain *chain); ++void dxgi_vk_swap_chain_latency_sleep(struct dxgi_vk_swap_chain *chain); ++void dxgi_vk_swap_chain_set_latency_sleep_mode(struct dxgi_vk_swap_chain *chain, + bool low_latency_mode, bool low_latency_boost, uint32_t minimum_interval_us); -+HRESULT dxgi_vk_swap_chain_set_latency_marker(struct dxgi_vk_swap_chain* chain, ++void dxgi_vk_swap_chain_set_latency_marker(struct dxgi_vk_swap_chain *chain, + uint64_t frameID, VkLatencyMarkerNV marker); -+HRESULT dxgi_vk_swap_chain_get_latency_info(struct dxgi_vk_swap_chain* chain, ++void dxgi_vk_swap_chain_get_latency_info(struct dxgi_vk_swap_chain *chain, + D3D12_LATENCY_RESULTS *latency_results); ++ ++ULONG dxgi_vk_swap_chain_incref(struct dxgi_vk_swap_chain *chain); ++ULONG dxgi_vk_swap_chain_decref(struct dxgi_vk_swap_chain *chain); + HRESULT dxgi_vk_swap_chain_factory_init(struct d3d12_command_queue *queue, struct dxgi_vk_swap_chain_factory *chain); @@ -1182,13 +1538,21 @@ index 124cd75a..16234e94 100644 LONG refcount; D3D12_COMMAND_QUEUE_DESC desc; -@@ -4266,6 +4287,19 @@ struct vkd3d_cached_command_allocator +@@ -4442,6 +4467,7 @@ enum vkd3d_queue_family + + struct vkd3d_queue_family_info + { ++ struct vkd3d_queue *out_of_band_queue; + struct vkd3d_queue **queues; + uint32_t queue_count; + uint32_t vk_family_index; +@@ -4456,6 +4482,19 @@ struct vkd3d_cached_command_allocator uint32_t vk_family_index; }; +struct vkd3d_device_swapchain_info +{ -+ struct dxgi_vk_swap_chain* low_latency_swapchain; ++ struct dxgi_vk_swap_chain *low_latency_swapchain; + uint32_t swapchain_count; +}; + @@ -1202,7 +1566,7 @@ index 124cd75a..16234e94 100644 /* ID3D12Device */ typedef ID3D12Device12 d3d12_device_iface; -@@ -4278,6 +4312,9 @@ typedef ID3D12DeviceExt d3d12_device_vkd3d_ext_iface; +@@ -4468,6 +4507,9 @@ typedef ID3D12DeviceExt d3d12_device_vkd3d_ext_iface; /* ID3D12DXVKInteropDevice */ typedef ID3D12DXVKInteropDevice d3d12_dxvk_interop_device_iface; @@ -1212,7 +1576,7 @@ index 124cd75a..16234e94 100644 struct d3d12_device_scratch_pool { struct vkd3d_scratch_buffer scratch_buffers[VKD3D_MAX_SCRATCH_BUFFER_COUNT]; -@@ -4292,6 +4329,7 @@ struct d3d12_device +@@ -4591,6 +4633,7 @@ struct d3d12_device d3d12_device_iface ID3D12Device_iface; d3d12_device_vkd3d_ext_iface ID3D12DeviceExt_iface; d3d12_dxvk_interop_device_iface ID3D12DXVKInteropDevice_iface; @@ -1220,7 +1584,15 @@ index 124cd75a..16234e94 100644 LONG refcount; VkDevice vk_device; -@@ -4362,6 +4400,9 @@ struct d3d12_device +@@ -4600,6 +4643,7 @@ struct d3d12_device + + pthread_mutex_t mutex; + pthread_mutex_t global_submission_mutex; ++ spinlock_t low_latency_swapchain_spinlock; + + VkPhysicalDeviceMemoryProperties memory_properties; + +@@ -4662,6 +4706,9 @@ struct d3d12_device #endif uint64_t shader_interface_key; uint32_t device_has_dgc_templates; @@ -1230,45 +1602,46 @@ index 124cd75a..16234e94 100644 }; HRESULT d3d12_device_create(struct vkd3d_instance *instance, -@@ -4584,6 +4625,31 @@ UINT d3d12_determine_shading_rate_image_tile_size(struct d3d12_device *device); +@@ -4885,6 +4932,32 @@ UINT d3d12_determine_shading_rate_image_tile_size(struct d3d12_device *device); bool d3d12_device_supports_required_subgroup_size_for_stage( struct d3d12_device *device, VkShaderStageFlagBits stage); +static inline void d3d12_device_register_swapchain(struct d3d12_device* device, struct dxgi_vk_swap_chain* swapchain) +{ -+ if (!device->swapchain_info.low_latency_swapchain && -+ device->swapchain_info.swapchain_count == 0) -+ { ++ spinlock_acquire(&device->low_latency_swapchain_spinlock); ++ ++ if (!device->swapchain_info.low_latency_swapchain && device->swapchain_info.swapchain_count == 0) + device->swapchain_info.low_latency_swapchain = swapchain; -+ } + else -+ { + device->swapchain_info.low_latency_swapchain = NULL; -+ } + + device->swapchain_info.swapchain_count++; ++ ++ spinlock_release(&device->low_latency_swapchain_spinlock); +} + +static inline void d3d12_device_remove_swapchain(struct d3d12_device* device, struct dxgi_vk_swap_chain* swapchain) +{ ++ spinlock_acquire(&device->low_latency_swapchain_spinlock); ++ + if (device->swapchain_info.low_latency_swapchain == swapchain) -+ { + device->swapchain_info.low_latency_swapchain = NULL; -+ } + + device->swapchain_info.swapchain_count--; ++ ++ spinlock_release(&device->low_latency_swapchain_spinlock); +} + /* ID3DBlob */ struct d3d_blob { diff --git a/libs/vkd3d/vulkan_procs.h b/libs/vkd3d/vulkan_procs.h -index 6b32bca1..554d223a 100644 +index e3b672a0e1..96f673dda7 100644 --- a/libs/vkd3d/vulkan_procs.h +++ b/libs/vkd3d/vulkan_procs.h -@@ -347,6 +347,13 @@ VK_DEVICE_EXT_PFN(vkSetDeviceMemoryPriorityEXT) - VK_DEVICE_EXT_PFN(vkCmdDecompressMemoryNV) - VK_DEVICE_EXT_PFN(vkCmdDecompressMemoryIndirectCountNV) +@@ -354,6 +354,13 @@ VK_DEVICE_EXT_PFN(vkCmdDecompressMemoryIndirectCountNV) + /* VK_EXT_device_fault */ + VK_DEVICE_EXT_PFN(vkGetDeviceFaultInfoEXT) +/* VK_NV_low_latency2 */ +VK_DEVICE_EXT_PFN(vkSetLatencySleepModeNV) @@ -1280,5 +1653,103 @@ index 6b32bca1..554d223a 100644 #undef VK_INSTANCE_PFN #undef VK_INSTANCE_EXT_PFN #undef VK_DEVICE_PFN --- -2.43.0 + +From f462223e05ec4b3674a435d4f1092416ab2412ee Mon Sep 17 00:00:00 2001 +From: Eric Sullivan +Date: Wed, 14 Feb 2024 20:03:00 -0800 +Subject: [PATCH] vkd3d: Add support for conditionally enabling an extension + with a minimum spec version + +--- + libs/vkd3d/device.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c +index 0b1bd8766e..5701b34456 100644 +--- a/libs/vkd3d/device.c ++++ b/libs/vkd3d/device.c +@@ -42,15 +42,18 @@ struct vkd3d_optional_extension_info + ptrdiff_t vulkan_info_offset; + uint64_t enable_config_flags; + uint64_t disable_config_flags; ++ uint32_t minimum_spec_version; + }; + + #define VK_EXTENSION(name, member) \ +- {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), 0} ++ {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), 0, 0} + + #define VK_EXTENSION_COND(name, member, required_flags) \ +- {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), required_flags} ++ {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), required_flags, 0} + #define VK_EXTENSION_DISABLE_COND(name, member, disable_flags) \ +- {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), 0, disable_flags} ++ {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), 0, disable_flags, 0} ++#define VK_EXTENSION_VERSION(name, member, spec_version) \ ++ {VK_ ## name ## _EXTENSION_NAME, offsetof(struct vkd3d_vulkan_info, member), 0, 0, spec_version} + + static const struct vkd3d_optional_extension_info optional_instance_extensions[] = + { +@@ -159,7 +162,7 @@ static bool is_extension_disabled(const char *extension_name) + } + + static bool has_extension(const VkExtensionProperties *extensions, +- unsigned int count, const char *extension_name) ++ unsigned int count, const char *extension_name, uint32_t minimum_spec_version) + { + unsigned int i; + +@@ -170,7 +173,8 @@ static bool has_extension(const VkExtensionProperties *extensions, + WARN("Extension %s is disabled.\n", debugstr_a(extension_name)); + continue; + } +- if (!strcmp(extensions[i].extensionName, extension_name)) ++ if (!strcmp(extensions[i].extensionName, extension_name) && ++ (extensions[i].specVersion >= minimum_spec_version)) + return true; + } + return false; +@@ -188,7 +192,7 @@ static unsigned int vkd3d_check_extensions(const VkExtensionProperties *extensio + + for (i = 0; i < required_extension_count; ++i) + { +- if (!has_extension(extensions, count, required_extensions[i])) ++ if (!has_extension(extensions, count, required_extensions[i], 0)) + ERR("Required %s extension %s is not supported.\n", + extension_type, debugstr_a(required_extensions[i])); + ++extension_count; +@@ -199,6 +203,7 @@ static unsigned int vkd3d_check_extensions(const VkExtensionProperties *extensio + uint64_t disable_flags = optional_extensions[i].disable_config_flags; + const char *extension_name = optional_extensions[i].extension_name; + uint64_t enable_flags = optional_extensions[i].enable_config_flags; ++ uint32_t minimum_spec_version = optional_extensions[i].minimum_spec_version; + ptrdiff_t offset = optional_extensions[i].vulkan_info_offset; + bool *supported = (void *)((uintptr_t)vulkan_info + offset); + +@@ -207,7 +212,7 @@ static unsigned int vkd3d_check_extensions(const VkExtensionProperties *extensio + if (disable_flags && (vkd3d_config_flags & disable_flags)) + continue; + +- if ((*supported = has_extension(extensions, count, extension_name))) ++ if ((*supported = has_extension(extensions, count, extension_name, minimum_spec_version))) + { + TRACE("Found %s extension.\n", debugstr_a(extension_name)); + ++extension_count; +@@ -216,7 +221,7 @@ static unsigned int vkd3d_check_extensions(const VkExtensionProperties *extensio + + for (i = 0; i < user_extension_count; ++i) + { +- if (!has_extension(extensions, count, user_extensions[i])) ++ if (!has_extension(extensions, count, user_extensions[i], 0)) + ERR("Required user %s extension %s is not supported.\n", + extension_type, debugstr_a(user_extensions[i])); + ++extension_count; +@@ -225,7 +230,7 @@ static unsigned int vkd3d_check_extensions(const VkExtensionProperties *extensio + assert(!optional_user_extension_count || user_extension_supported); + for (i = 0; i < optional_user_extension_count; ++i) + { +- if (has_extension(extensions, count, optional_user_extensions[i])) ++ if (has_extension(extensions, count, optional_user_extensions[i], 0)) + { + user_extension_supported[i] = true; + ++extension_count;