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 <dpiliaiev@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27727>
This commit is contained in:
Danylo Piliaiev 2024-02-21 16:28:59 +01:00 committed by Marge Bot
parent 7a6836611e
commit f4c40fc89c
5 changed files with 35 additions and 0 deletions

View file

@ -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

View file

@ -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)

View file

@ -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.
*/

View file

@ -1327,4 +1327,16 @@ TODO: document the other workarounds.
<option name="force_gl_vendor" value="Qualcomm"/>
</application>
</device>
<device driver="turnip">
<!-- Up to DXVK version 2.3.0 -->
<engine engine_name_match="DXVK" engine_versions="0:8400896">
<!--
See: https://github.com/doitsujin/dxvk/issues/3861
The shader-defined array size is entirely meaningless in D3D.
-->
<option name="tu_allow_oob_indirect_ubo_loads" value="true" />
</engine>
</device>
</driconf>

View file

@ -594,6 +594,10 @@
DRI_CONF_OPT_B(tu_dont_reserve_descriptor_set, def, \
"Don't internally reserve one of the HW descriptor sets for descriptor set dynamic offset support, this frees up an extra descriptor set at the cost of that feature")
#define DRI_CONF_TU_ALLOW_OOB_INDIRECT_UBO_LOADS(def) \
DRI_CONF_OPT_B(tu_allow_oob_indirect_ubo_loads, def, \
"Some D3D11 games rely on out-of-bounds indirect UBO loads to return real values from underlying bound descriptor, this prevents us from lowering indirectly accessed UBOs to consts")
/**
* \brief venus specific configuration options
*/