/* * 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. */ void anv_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); } VkResult anv_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); } void anv_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); }