From 331af5e746b48131eedaa168f37ea9b1cb5580a3 Mon Sep 17 00:00:00 2001 From: "Thomas H.P. Andersen" Date: Thu, 12 Feb 2026 13:01:35 +0100 Subject: [PATCH] nvk: add app workaround layer This adopts the device internal app workaround layer from radv The layer allows to fix up game input in the layer instead of adding workarounds within the driver. Initially this only includes the workaround for Metro exodus as I have verified that it fixes a crash on NVK. Follow up commits can add the other relevant workarounds when the fixes are verified to be needed for NVK. Reviewed-by: Mary Guillemard Part-of: --- .../vulkan/layers/nvk_app_workarounds.c | 30 +++++++++++++++++++ .../vulkan/layers/nvk_app_workarounds.h | 15 ++++++++++ src/nouveau/vulkan/meson.build | 2 ++ src/nouveau/vulkan/nvk_device.c | 21 +++++++++++++ src/nouveau/vulkan/nvk_device.h | 2 ++ src/nouveau/vulkan/nvk_instance.c | 3 ++ src/nouveau/vulkan/nvk_instance.h | 1 + src/util/00-mesa-defaults.conf | 3 ++ src/util/driconf.h | 6 ++++ 9 files changed, 83 insertions(+) create mode 100644 src/nouveau/vulkan/layers/nvk_app_workarounds.c create mode 100644 src/nouveau/vulkan/layers/nvk_app_workarounds.h diff --git a/src/nouveau/vulkan/layers/nvk_app_workarounds.c b/src/nouveau/vulkan/layers/nvk_app_workarounds.c new file mode 100644 index 00000000000..d67fb949e98 --- /dev/null +++ b/src/nouveau/vulkan/layers/nvk_app_workarounds.c @@ -0,0 +1,30 @@ +/* + * Copyright © 2026 Valve Corporation + * + * SPDX-License-Identifier: MIT + */ + +#include "vk_framebuffer.h" + +#include "nvk_cmd_buffer.h" +#include "nvk_device.h" +#include "nvk_entrypoints.h" +#include "nvk_image_view.h" + +#include "layers/nvk_app_workarounds.h" + +/* This layer implements various application WAs that don't need to be in the core driver. */ + +/* Metro Exodus */ +VKAPI_ATTR VkResult VKAPI_CALL +metro_exodus_GetSemaphoreCounterValue(VkDevice _device, VkSemaphore _semaphore, uint64_t *pValue) +{ + /* See https://gitlab.freedesktop.org/mesa/mesa/-/issues/5119. */ + if (_semaphore == VK_NULL_HANDLE) { + fprintf(stderr, "NVK: Ignoring vkGetSemaphoreCounterValue() with NULL semaphore (game bug)!\n"); + return VK_SUCCESS; + } + + VK_FROM_HANDLE(nvk_device, device, _device); + return device->layer_dispatch.app.GetSemaphoreCounterValue(_device, _semaphore, pValue); +} diff --git a/src/nouveau/vulkan/layers/nvk_app_workarounds.h b/src/nouveau/vulkan/layers/nvk_app_workarounds.h new file mode 100644 index 00000000000..4af18510346 --- /dev/null +++ b/src/nouveau/vulkan/layers/nvk_app_workarounds.h @@ -0,0 +1,15 @@ +/* + * Copyright © 2026 Valve Corporation + * + * SPDX-License-Identifier: MIT + */ + +#ifndef NVK_APP_WORKAROUNDS_H +#define NVK_APP_WORKAROUNDS_H + +#include + +VKAPI_ATTR VkResult VKAPI_CALL metro_exodus_GetSemaphoreCounterValue(VkDevice _device, VkSemaphore _semaphore, + uint64_t *pValue); + +#endif /* NVK_APP_WORKAROUNDS_H */ diff --git a/src/nouveau/vulkan/meson.build b/src/nouveau/vulkan/meson.build index 9e91c135da8..8c2a462615f 100644 --- a/src/nouveau/vulkan/meson.build +++ b/src/nouveau/vulkan/meson.build @@ -67,6 +67,8 @@ nvk_files = files( 'nvk_upload_queue.h', 'nvk_wsi.c', 'nvk_wsi.h', + 'layers/nvk_app_workarounds.c', + 'layers/nvk_app_workarounds.h', 'nvkmd/nouveau/nvkmd_nouveau.h', 'nvkmd/nouveau/nvkmd_nouveau_ctx.c', 'nvkmd/nouveau/nvkmd_nouveau_dev.c', diff --git a/src/nouveau/vulkan/nvk_device.c b/src/nouveau/vulkan/nvk_device.c index bcc59b18627..0514113d136 100644 --- a/src/nouveau/vulkan/nvk_device.c +++ b/src/nouveau/vulkan/nvk_device.c @@ -10,6 +10,7 @@ #include "nvk_physical_device.h" #include "nvk_sampler.h" #include "nvk_shader.h" +#include "layers/nvk_app_workarounds.h" #include "nvkmd/nvkmd.h" #include "vk_common_entrypoints.h" @@ -192,11 +193,31 @@ add_entrypoints(struct dispatch_table_builder *b, const struct vk_device_entrypo if (table < NVK_DISPATCH_TABLE_COUNT) b->used[table] = true; } + +static void +init_app_workarounds_entrypoints(struct nvk_device *device, struct dispatch_table_builder *b) +{ + const struct nvk_physical_device *pdev = nvk_device_physical(device); + const struct nvk_instance *instance = nvk_physical_device_instance(pdev); + struct vk_device_entrypoint_table table = {0}; + +#define SET_ENTRYPOINT(app_layer, entrypoint) table.entrypoint = app_layer##_##entrypoint; + if (!strcmp(instance->app_layer, "metroexodus")) { + SET_ENTRYPOINT(metro_exodus, GetSemaphoreCounterValue); + } +#undef SET_ENTRYPOINT + + add_entrypoints(b, &table, NVK_APP_DISPATCH_TABLE); +} + static void init_dispatch_tables(struct nvk_device *dev) { struct dispatch_table_builder b = {0}; b.tables[NVK_DEVICE_DISPATCH_TABLE] = &dev->vk.dispatch_table; + b.tables[NVK_APP_DISPATCH_TABLE] = &dev->layer_dispatch.app; + + init_app_workarounds_entrypoints(dev, &b); add_entrypoints(&b, &nvk_device_entrypoints, NVK_DISPATCH_TABLE_COUNT); add_entrypoints(&b, &wsi_device_entrypoints, NVK_DISPATCH_TABLE_COUNT); diff --git a/src/nouveau/vulkan/nvk_device.h b/src/nouveau/vulkan/nvk_device.h index 200363b95d5..5359e663adb 100644 --- a/src/nouveau/vulkan/nvk_device.h +++ b/src/nouveau/vulkan/nvk_device.h @@ -23,10 +23,12 @@ struct vk_pipeline_cache; enum nvk_dispatch_table { NVK_DEVICE_DISPATCH_TABLE, + NVK_APP_DISPATCH_TABLE, NVK_DISPATCH_TABLE_COUNT, }; struct nvk_layer_dispatch_tables { + struct vk_device_dispatch_table app; }; struct nvk_slm_area { diff --git a/src/nouveau/vulkan/nvk_instance.c b/src/nouveau/vulkan/nvk_instance.c index 730fd293470..ce62037edef 100644 --- a/src/nouveau/vulkan/nvk_instance.c +++ b/src/nouveau/vulkan/nvk_instance.c @@ -111,6 +111,7 @@ static const driOptionDescription nvk_dri_options[] = { DRI_CONF_VK_WSI_FORCE_SWAPCHAIN_TO_CURRENT_EXTENT(false) DRI_CONF_VK_X11_IGNORE_SUBOPTIMAL(false) DRI_CONF_VK_ZERO_VRAM(false) + DRI_CONF_NVK_APP_LAYER() DRI_CONF_SECTION_END }; @@ -127,6 +128,8 @@ nvk_init_dri_options(struct nvk_instance *instance) if (driQueryOptionb(&instance->dri_options, "vk_zero_vram")) instance->debug_flags |= NVK_DEBUG_ZERO_MEMORY; + + instance->app_layer = driQueryOptionstr(&instance->dri_options, "nvk_app_layer"); } VKAPI_ATTR VkResult VKAPI_CALL diff --git a/src/nouveau/vulkan/nvk_instance.h b/src/nouveau/vulkan/nvk_instance.h index a5d0cc23d7a..4e9ef5681fa 100644 --- a/src/nouveau/vulkan/nvk_instance.h +++ b/src/nouveau/vulkan/nvk_instance.h @@ -18,6 +18,7 @@ struct nvk_instance { struct driOptionCache dri_options; struct driOptionCache available_dri_options; + char *app_layer; uint8_t driver_build_sha[SHA1_DIGEST_LENGTH]; uint32_t force_vk_vendor; diff --git a/src/util/00-mesa-defaults.conf b/src/util/00-mesa-defaults.conf index e10a0d9d1cb..5da30ccdae1 100644 --- a/src/util/00-mesa-defaults.conf +++ b/src/util/00-mesa-defaults.conf @@ -1198,6 +1198,9 @@ TODO: document the other workarounds.