From f4c40fc89c7e53a2c0f2f78578fe10b71a4e27f1 Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Wed, 21 Feb 2024 16:28:59 +0100 Subject: [PATCH] tu: Add workaround for D3D11 games accessing UBO out of bounds Some D3D11 games rely on out-of-bounds indirect UBO loads to return real values from underlying bound descriptor. This workaround would prevent us from lowering indirectly accessed UBOs to consts. Later DXVK would declare dynamically indexed uniforms with upper size bound, to make the accesses spec compliant. But for now we need our own workaround. Known affected games: - Dark Souls 3 - Sekiro: Shadows Die Twice - Final Fantasy Type-0 HD - Ultrakill - Dishonored 2 DXVK discussions: - https://github.com/doitsujin/dxvk/issues/405 - https://github.com/doitsujin/dxvk/issues/3861 Signed-off-by: Danylo Piliaiev Part-of: --- src/freedreno/vulkan/tu_device.cc | 3 +++ src/freedreno/vulkan/tu_device.h | 8 ++++++++ src/freedreno/vulkan/tu_shader.cc | 8 ++++++++ src/util/00-mesa-defaults.conf | 12 ++++++++++++ src/util/driconf.h | 4 ++++ 5 files changed, 35 insertions(+) diff --git a/src/freedreno/vulkan/tu_device.cc b/src/freedreno/vulkan/tu_device.cc index 61a7586c28b..5651510a683 100644 --- a/src/freedreno/vulkan/tu_device.cc +++ b/src/freedreno/vulkan/tu_device.cc @@ -801,6 +801,7 @@ static const driOptionDescription tu_dri_options[] = { DRI_CONF_SECTION_MISCELLANEOUS DRI_CONF_DISABLE_CONSERVATIVE_LRZ(false) DRI_CONF_TU_DONT_RESERVE_DESCRIPTOR_SET(false) + DRI_CONF_TU_ALLOW_OOB_INDIRECT_UBO_LOADS(false) DRI_CONF_SECTION_END }; @@ -819,6 +820,8 @@ tu_init_dri_options(struct tu_instance *instance) !driQueryOptionb(&instance->dri_options, "disable_conservative_lrz"); instance->reserve_descriptor_set = !driQueryOptionb(&instance->dri_options, "tu_dont_reserve_descriptor_set"); + instance->allow_oob_indirect_ubo_loads = + driQueryOptionb(&instance->dri_options, "tu_allow_oob_indirect_ubo_loads"); } VKAPI_ATTR VkResult VKAPI_CALL diff --git a/src/freedreno/vulkan/tu_device.h b/src/freedreno/vulkan/tu_device.h index 0bbbbf60883..22d8d6fdd19 100644 --- a/src/freedreno/vulkan/tu_device.h +++ b/src/freedreno/vulkan/tu_device.h @@ -166,6 +166,14 @@ struct tu_instance * core, this is enabled by default. */ bool reserve_descriptor_set; + + /* Allow out of bounds UBO access by disabling lowering of UBO loads for + * indirect access, which rely on the UBO bounds specified in the shader, + * rather than the bound UBO size which isn't known until draw time. + * + * See: https://github.com/doitsujin/dxvk/issues/3861 + */ + bool allow_oob_indirect_ubo_loads; }; VK_DEFINE_HANDLE_CASTS(tu_instance, vk.base, VkInstance, VK_OBJECT_TYPE_INSTANCE) diff --git a/src/freedreno/vulkan/tu_shader.cc b/src/freedreno/vulkan/tu_shader.cc index 5b511a1734c..7abf5c2a343 100644 --- a/src/freedreno/vulkan/tu_shader.cc +++ b/src/freedreno/vulkan/tu_shader.cc @@ -312,6 +312,14 @@ lower_ssbo_ubo_intrinsic(struct tu_device *dev, nir_scalar scalar_idx = nir_scalar_resolved(intrin->src[buffer_src].ssa, 0); nir_def *descriptor_idx = nir_channel(b, intrin->src[buffer_src].ssa, 1); + if (intrin->intrinsic == nir_intrinsic_load_ubo && + dev->instance->allow_oob_indirect_ubo_loads) { + nir_scalar offset = nir_scalar_resolved(intrin->src[1].ssa, 0); + if (!nir_scalar_is_const(offset)) { + nir_intrinsic_set_range(intrin, ~0); + } + } + /* For isam, we need to use the appropriate descriptor if 16-bit storage is * enabled. Descriptor 0 is the 16-bit one, descriptor 1 is the 32-bit one. */ diff --git a/src/util/00-mesa-defaults.conf b/src/util/00-mesa-defaults.conf index e5a03cc7b47..6202f78ed3b 100644 --- a/src/util/00-mesa-defaults.conf +++ b/src/util/00-mesa-defaults.conf @@ -1327,4 +1327,16 @@ TODO: document the other workarounds.