From c2acd9f76aa7406d801f92d82a766442bdd44845 Mon Sep 17 00:00:00 2001 From: Sviatoslav Peleshko Date: Thu, 3 Nov 2022 01:41:53 +0200 Subject: [PATCH] anv: Add layer with work-around for Doom 64 texture corruption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7817 Signed-off-by: Sviatoslav Peleshko Reviewed-by: Tapani Pälli Part-of: --- src/intel/vulkan/anv_device.c | 8 ++ src/intel/vulkan/anv_private.h | 8 ++ src/intel/vulkan/layers/anv_doom64.c | 134 +++++++++++++++++++++++++++ src/intel/vulkan/meson.build | 2 + 4 files changed, 152 insertions(+) create mode 100644 src/intel/vulkan/layers/anv_doom64.c diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index fa75222efad..d166341ff1d 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -3302,6 +3302,12 @@ VkResult anv_CreateDevice( vk_device_dispatch_table_from_entrypoints(&dispatch_table, &hitman3_device_entrypoints, true); override_initial_entrypoints = false; } + if (physical_device->info.ver < 12 && + physical_device->instance->vk.app_info.app_name && + !strcmp(physical_device->instance->vk.app_info.app_name, "DOOM 64")) { + vk_device_dispatch_table_from_entrypoints(&dispatch_table, &doom64_device_entrypoints, true); + override_initial_entrypoints = false; + } vk_device_dispatch_table_from_entrypoints(&dispatch_table, anv_genX(&physical_device->info, device_entrypoints), override_initial_entrypoints); @@ -3545,6 +3551,8 @@ VkResult anv_CreateDevice( "Anv") + 8, 8), }; + device->workarounds.doom64_images = NULL; + device->rt_uuid_addr = anv_address_add(device->workaround_address, 8); memcpy(device->rt_uuid_addr.bo->map + device->rt_uuid_addr.offset, physical_device->rt_uuid, diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index e506caf93c8..4250bf219f7 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -60,6 +60,7 @@ #include "util/hash_table.h" #include "util/list.h" #include "util/perf/u_trace.h" +#include "util/set.h" #include "util/sparse_array.h" #include "util/u_atomic.h" #include "util/u_vector.h" @@ -1202,6 +1203,13 @@ struct anv_device { struct anv_bo * workaround_bo; struct anv_address workaround_address; + /** + * Workarounds for game bugs. + */ + struct { + struct set * doom64_images; + } workarounds; + struct anv_bo * trivial_batch_bo; struct anv_state null_surface_state; diff --git a/src/intel/vulkan/layers/anv_doom64.c b/src/intel/vulkan/layers/anv_doom64.c new file mode 100644 index 00000000000..80ca74f9791 --- /dev/null +++ b/src/intel/vulkan/layers/anv_doom64.c @@ -0,0 +1,134 @@ +/* + * Copyright © 2022 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "util/set.h" +#include "anv_private.h" +#include "vk_common_entrypoints.h" + +/** + * The DOOM 64 rendering corruption is happening because the game always uses + * ``` + * vkCmdPipelineBarrier(VK_IMAGE_LAYOUT_UNDEFINED -> + * VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + * vkCmdCopyBufferToImage(...) + * vkCmdPipelineBarrier(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL -> + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + * ``` + * when it wants to update its texture atlas image. + * + * According to spec, transitioning from VK_IMAGE_LAYOUT_UNDEFINED means + * that the current image content might be discarded, but the game relies + * on it being fully preserved. + * + * This work-around layer implements super-barebone layout tracking: allows + * the first transition from VK_IMAGE_LAYOUT_UNDEFINED, but replaces + * oldLayout with VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL for each + * subsequent transition of that image. + * + * Gen12+ does not ambiguate CCS data on transition from VK_IMAGE_LAYOUT_UNDEFINED + * so it preserves all compressed information, and this WA is not needed. + */ + +VKAPI_ATTR void VKAPI_CALL +doom64_CmdPipelineBarrier(VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags dstStageMask, + VkDependencyFlags dependencyFlags, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers) +{ + ANV_FROM_HANDLE(anv_cmd_buffer, command_buffer, commandBuffer); + assert(command_buffer && command_buffer->device); + + VkImageMemoryBarrier fixed_barrier; + struct set * defined_images = + command_buffer->device->workarounds.doom64_images; + + if (defined_images && + imageMemoryBarrierCount == 1 && pImageMemoryBarriers && + pImageMemoryBarriers[0].oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && + pImageMemoryBarriers[0].newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + ANV_FROM_HANDLE(anv_image, image, pImageMemoryBarriers[0].image); + + if (!_mesa_set_search(defined_images, image)) { + _mesa_set_add(defined_images, image); + } else { + memcpy(&fixed_barrier, pImageMemoryBarriers, sizeof(VkImageMemoryBarrier)); + + fixed_barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + pImageMemoryBarriers = (const VkImageMemoryBarrier*) &fixed_barrier; + } + } + + vk_common_CmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, + dependencyFlags, memoryBarrierCount, + pMemoryBarriers, bufferMemoryBarrierCount, + pBufferMemoryBarriers, + imageMemoryBarrierCount, + pImageMemoryBarriers); +} + +VKAPI_ATTR VkResult VKAPI_CALL +doom64_CreateImage(VkDevice _device, const VkImageCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, VkImage* pImage) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + assert(device); + + if (!device->workarounds.doom64_images) { + device->workarounds.doom64_images = _mesa_pointer_set_create(NULL); + + if (!device->workarounds.doom64_images) { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + return anv_CreateImage(_device, pCreateInfo, pAllocator, pImage); +} + +VKAPI_ATTR void VKAPI_CALL +doom64_DestroyImage(VkDevice _device, VkImage _image, + const VkAllocationCallbacks *pAllocator) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + ANV_FROM_HANDLE(anv_image, image, _image); + assert(device); + + struct set * defined_images = device->workarounds.doom64_images; + + if (image && defined_images) { + _mesa_set_remove_key(defined_images, image); + + if (!defined_images->entries) { + _mesa_set_destroy(defined_images, NULL); + device->workarounds.doom64_images = NULL; + } + } + + anv_DestroyImage(_device, _image, pAllocator); +} diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build index 2a1f46dfb34..d09960a4b8c 100644 --- a/src/intel/vulkan/meson.build +++ b/src/intel/vulkan/meson.build @@ -40,6 +40,7 @@ anv_entrypoints = custom_target( '--device-prefix', 'gfx11', '--device-prefix', 'gfx12', '--device-prefix', 'gfx125', + '--device-prefix', 'doom64', '--device-prefix', 'hitman3' ], depend_files : vk_entrypoints_gen_depend_files, @@ -131,6 +132,7 @@ foreach g : [['90', ['gfx8_cmd_buffer.c']], endforeach libanv_files = files( + 'layers/anv_doom64.c', 'layers/anv_hitman3.c', 'anv_allocator.c', 'anv_android.h',