diff options
author | esullivan-nvidia <esullivan@nvidia.com> | 2022-10-05 13:10:16 +0300 |
---|---|---|
committer | Hans-Kristian Arntzen <post@arntzen-software.no> | 2022-10-11 12:36:42 +0300 |
commit | f97edc79ff06065628588cfcaf26d48b2220328b (patch) | |
tree | 3271a9e5bcd244b6b4033a9858ebd918c399be29 | |
parent | c42f24a2b0da37f03758f1ab97f3fa98b082c2e0 (diff) |
vkd3d: Add PREALLOCATE_SRV_MIP_CLAMPS workaround for Halo Infinite
Halo Infinite currently has a race condition that can result in a GPU fault on
NVIDIA hardware. The root cause of this race condition is the application overwriting
existing SRV descriptors with a new mip clamp value asynchronously to the applications GPU
submission timeline. This is problematic for vkd3d because it requires creating a new VkImageView
to represent the SRV with the updated mip clamp value. If this SRV is being created after
work has been submitted that accesses it, the GPU may not see the correct descriptor state
possibly resulting in a fault.
This commit adds the VKD3D_CONFIG_FLAG_PREALLOCATE_SRV_MIP_CLAMPS configuration as a workaround to
the race condition. It works by preallocating all the VkImageViews for each possible mip clamp level
the application may attempt to create for the resource. Technically this is still a race condition
but the end result isn't a GPU fault if the race condition is lost. Instead the shader will just sample
from the texture with the previous SRVs mip clamp level rather than the updated one. These are
the same outcomes that are possible on RADV without this workaround.
Signed-off-by: Eric Sullivan <esullivan@nvidia.com>
-rw-r--r-- | include/vkd3d.h | 1 | ||||
-rw-r--r-- | libs/vkd3d/device.c | 3 | ||||
-rw-r--r-- | libs/vkd3d/resource.c | 25 |
3 files changed, 28 insertions, 1 deletions
diff --git a/include/vkd3d.h b/include/vkd3d.h index 907e4f0f..b0817a04 100644 --- a/include/vkd3d.h +++ b/include/vkd3d.h @@ -92,6 +92,7 @@ extern "C" { #define VKD3D_CONFIG_FLAG_ALLOW_SBT_COLLECTION (1ull << 30) #define VKD3D_CONFIG_FLAG_FORCE_NATIVE_FP16 (1ull << 31) #define VKD3D_CONFIG_FLAG_USE_HOST_IMPORT_FALLBACK (1ull << 32) +#define VKD3D_CONFIG_FLAG_PREALLOCATE_SRV_MIP_CLAMPS (1ull << 33) typedef HRESULT (*PFN_vkd3d_signal_event)(HANDLE event); diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 3b60a151..b9ad3afe 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -521,7 +521,7 @@ static const struct vkd3d_instance_application_meta application_override[] = { * Game also relies on indirectly modifying CBV root descriptors, which means we are forced to rely on RAW_VA_CBV. */ { VKD3D_STRING_COMPARE_EXACT, "HaloInfinite.exe", VKD3D_CONFIG_FLAG_ZERO_MEMORY_WORKAROUNDS_COMMITTED_BUFFER_UAV | VKD3D_CONFIG_FLAG_FORCE_RAW_VA_CBV | - VKD3D_CONFIG_FLAG_USE_HOST_IMPORT_FALLBACK, 0 }, + VKD3D_CONFIG_FLAG_USE_HOST_IMPORT_FALLBACK | VKD3D_CONFIG_FLAG_PREALLOCATE_SRV_MIP_CLAMPS, 0 }, /* (1182900) Workaround amdgpu kernel bug with host memory import and concurrent submissions. */ { VKD3D_STRING_COMPARE_EXACT, "APlagueTaleRequiem_x64.exe", VKD3D_CONFIG_FLAG_USE_HOST_IMPORT_FALLBACK, 0 }, /* Shadow of the Tomb Raider (750920). @@ -719,6 +719,7 @@ static const struct vkd3d_debug_option vkd3d_config_options[] = {"force_raw_va_cbv", VKD3D_CONFIG_FLAG_FORCE_RAW_VA_CBV}, {"allow_sbt_collection", VKD3D_CONFIG_FLAG_ALLOW_SBT_COLLECTION}, {"host_import_fallback", VKD3D_CONFIG_FLAG_USE_HOST_IMPORT_FALLBACK}, + {"preallocate_srv_mip_clamps", VKD3D_CONFIG_FLAG_PREALLOCATE_SRV_MIP_CLAMPS}, }; static void vkd3d_config_flags_init_once(void) diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index f017ce6a..11f5ff30 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -20,6 +20,7 @@ #define VKD3D_DBG_CHANNEL VKD3D_DBG_CHANNEL_API #include <float.h> +#include <math.h> #include "vkd3d_private.h" #include "vkd3d_rw_spinlock.h" @@ -4432,6 +4433,30 @@ static void vkd3d_create_texture_srv(vkd3d_cpu_descriptor_va_t desc_va, if (key.u.texture.miplevel_count == VK_REMAINING_MIP_LEVELS) key.u.texture.miplevel_count = resource->desc.MipLevels - key.u.texture.miplevel_idx; + if ((vkd3d_config_flags & VKD3D_CONFIG_FLAG_PREALLOCATE_SRV_MIP_CLAMPS) && + desc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2DMS && + desc->ViewDimension != D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY) + { + key.u.texture.miplevel_clamp = floor(key.u.texture.miplevel_clamp); + + if (!hash_map_find(&resource->view_map.map, &key)) + { + uint32_t starting_mip = key.u.texture.miplevel_idx; + uint32_t mip_count = key.u.texture.miplevel_count != UINT32_MAX ? + key.u.texture.miplevel_count : + resource->desc.MipLevels - starting_mip; + uint32_t i; + + struct vkd3d_view_key preallocate_key = key; + + for (i = starting_mip; i < mip_count; i++) + { + preallocate_key.u.texture.miplevel_clamp = (float)(i); + vkd3d_view_map_create_view(&resource->view_map, device, &preallocate_key); + } + } + } + if (!(view = vkd3d_view_map_create_view(&resource->view_map, device, &key))) return; |