diff --git a/src/intel/vulkan_hasvk/anv_device.c b/src/intel/vulkan_hasvk/anv_device.c index 930816d033a..027182d4445 100644 --- a/src/intel/vulkan_hasvk/anv_device.c +++ b/src/intel/vulkan_hasvk/anv_device.c @@ -2712,8 +2712,16 @@ VkResult anv_CreateDevice( return vk_error(physical_device, VK_ERROR_OUT_OF_HOST_MEMORY); struct vk_device_dispatch_table dispatch_table; + + bool override_initial_entrypoints = true; + if (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), true); + anv_genX(&physical_device->info, device_entrypoints), + override_initial_entrypoints); vk_device_dispatch_table_from_entrypoints(&dispatch_table, &anv_device_entrypoints, false); vk_device_dispatch_table_from_entrypoints(&dispatch_table, @@ -2926,6 +2934,8 @@ VkResult anv_CreateDevice( "Anv") + 8, 8), }; + device->workarounds.doom64_images = NULL; + device->debug_frame_desc = intel_debug_get_identifier_block(device->workaround_bo->map, device->workaround_bo->size, diff --git a/src/intel/vulkan_hasvk/anv_private.h b/src/intel/vulkan_hasvk/anv_private.h index cae98d2513e..88abb06bc91 100644 --- a/src/intel/vulkan_hasvk/anv_private.h +++ b/src/intel/vulkan_hasvk/anv_private.h @@ -59,6 +59,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" @@ -1109,6 +1110,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_hasvk/layers/anv_doom64.c b/src/intel/vulkan_hasvk/layers/anv_doom64.c new file mode 100644 index 00000000000..181a120d9c4 --- /dev/null +++ b/src/intel/vulkan_hasvk/layers/anv_doom64.c @@ -0,0 +1,131 @@ +/* + * 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. + */ + +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_hasvk/meson.build b/src/intel/vulkan_hasvk/meson.build index fd99269246b..7fcbc3b42cf 100644 --- a/src/intel/vulkan_hasvk/meson.build +++ b/src/intel/vulkan_hasvk/meson.build @@ -27,6 +27,7 @@ anv_hasvk_entrypoints = custom_target( '--out-h', '@OUTPUT0@', '--out-c', '@OUTPUT1@', '--prefix', 'anv', '--device-prefix', 'gfx7', '--device-prefix', 'gfx75', '--device-prefix', 'gfx8', + '--device-prefix', 'doom64', ], depend_files : vk_entrypoints_gen_depend_files, ) @@ -98,6 +99,7 @@ foreach g : [['70', ['gfx7_cmd_buffer.c']], endforeach libanv_files = files( + 'layers/anv_doom64.c', 'anv_allocator.c', 'anv_android.h', 'anv_batch_chain.c',