anv: reimplement the anv_fake_nonlocal_memory workaround

Commit 94989b45a5 ("anv,driconf: Add fake non device local memory WA
for Total War: Warhammer 3") implemented a workaround to make
Warhammer 3 work on ADL, but the game still doesn't work on LNL, which
uses xe.ko, and MTL, which uses i915.ko: it still fails at launch
claiming it couldn't allocate memory.

So in this implementation, instead of clearing DEVICE_LOCAL_BIT we
just duplicate our memory types, one having the bit and one not
having.

v2:
 - Check for VK_MAX_MEMORY_TYPES (José)
 - Invert the order of the memory types (José)
 - Fix white space issue (José)
v3:
 - Comment our non-spec-compliance (José)
 - Remove useless lines (José)

Link: https://gitlab.freedesktop.org/mesa/mesa/-/issues/8721
Fixes: 94989b45a5 ("anv,driconf: Add fake non device local memory WA for Total War: Warhammer 3")
Reviewed-by: José Roberto de Souza <jose.souza@intel.com>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30162>
This commit is contained in:
Paulo Zanoni
2024-07-11 16:01:32 -07:00
committed by Marge Bot
parent cdf646dbc3
commit 241585667f

View File

@@ -2030,6 +2030,31 @@ anv_physical_device_init_heaps(struct anv_physical_device *device, int fd)
if (result != VK_SUCCESS)
return result;
/* Some games (e.g., Total War: WARHAMMER III) sometimes seem to expect to
* find memory types both with and without
* VK_MEMORY_TYPE_PROPERTY_DEVICE_LOCAL_BIT. So here we duplicate all our
* memory types just to make these games happy.
* This behavior is not spec-compliant as we still only have one heap that
* is now inconsistent with some of the memory types, but the game doesn't
* seem to care about it.
*/
if (device->instance->anv_fake_nonlocal_memory &&
!anv_physical_device_has_vram(device)) {
const uint32_t base_types_count = device->memory.type_count;
for (int i = 0; i < base_types_count; i++) {
if (!(device->memory.types[i].propertyFlags &
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))
continue;
struct anv_memory_type *new_type =
&device->memory.types[device->memory.type_count++];
*new_type = device->memory.types[i];
device->memory.types[i].propertyFlags &=
~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}
}
/* Replicate all non protected memory types for descriptor buffers because
* we want to identify memory allocations to place them in the right memory
* heap.
@@ -2069,6 +2094,8 @@ anv_physical_device_init_heaps(struct anv_physical_device *device, int fd)
new_type->descriptor_buffer = true;
}
assert(device->memory.type_count <= VK_MAX_MEMORY_TYPES);
for (unsigned i = 0; i < device->memory.type_count; i++) {
VkMemoryPropertyFlags props = device->memory.types[i].propertyFlags;
if ((props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
@@ -2934,26 +2961,6 @@ void anv_GetPhysicalDeviceMemoryProperties(
.flags = physical_device->memory.heaps[i].flags,
};
}
/* Some games (e.g. Total War: WARHAMMER III) sometimes completely refuse
* to use memory types with VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT set.
* On iGPUs we have only device-local memory, so we must hide it
* from the flags.
*
* Additionally, TW also seems to crash if a non-local but also
* non host-visible memory is present, so we should be careful which
* memory types we hide this flag from.
*/
if (physical_device->instance->anv_fake_nonlocal_memory &&
!anv_physical_device_has_vram(physical_device)) {
for (uint32_t i = 0; i < physical_device->memory.type_count; i++) {
if (pMemoryProperties->memoryTypes[i].propertyFlags &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
pMemoryProperties->memoryTypes[i].propertyFlags &=
~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}
}
}
}
static void