#include "graphics/host_gpu/renderer/renderTargetBarriers.h" #include "common/assert.h" #include "common/common.h" #include "common/logging/log.h" #include "common/profiler.h" #include "common/stringUtils.h" #include "common/threads.h" #include "graphics/guest_gpu/gpu_defs.h" #include "graphics/guest_gpu/hardwareContext.h" #include "graphics/guest_gpu/tile.h" #include "graphics/host_gpu/graphicContext.h" #include "graphics/host_gpu/objects/textureCommon.h" #include "graphics/host_gpu/renderer/framebufferCache.h" #include "graphics/host_gpu/renderer/imageView.h" #include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/renderContext.h" #include "graphics/host_gpu/transfer.h" #include "graphics/host_gpu/vulkanCommon.h" #include "graphics/presentation/displayBuffer.h" #include #include #include #include #include #include namespace Libs::Graphics { void GraphicsRenderMemoryBarrier(CommandBuffer& buffer) { EXIT_IF(buffer.IsInvalid()); Common::LockGuard lock(GetRenderContext().GetMutex()); auto vk_buffer = buffer.Handle(); VulkanMemoryBarrier mem_barrier {}; mem_barrier.sType = vk::StructureType::eMemoryBarrier; mem_barrier.pNext = nullptr; mem_barrier.srcAccessMask = vk::AccessFlagBits::eMemoryWrite; mem_barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eAllCommands, vk::DependencyFlags {}, 1, &mem_barrier, 0, nullptr, 0, nullptr); } void GraphicsRenderTextureBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) { vk::ImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eTransferWrite | vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eMemoryRead; image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; image_memory_barrier.oldLayout = image.layout; image_memory_barrier.newLayout = RENDER_COLOR_IMAGE_LAYOUT; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = image.image; image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = image.layers; vk_buffer.pipelineBarrier( vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eFragmentShader, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eComputeShader, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); image.layout = image_memory_barrier.newLayout; } void GraphicsRenderColorImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image, vk::ImageLayout new_layout) { if (image.layout != new_layout) { if (image.type == VulkanImageType::VideoOut && image.layout == vk::ImageLayout::eTransferDstOptimal) { static std::atomic log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 128) { LOGF("GraphicsRenderColorImageBarrier: image=%p type=%d layout=%s -> %s\n", VulkanHandleToPointer(image.image), static_cast(image.type), VulkanToString(image.layout).c_str(), VulkanToString(new_layout).c_str()); } } vk::ImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead; image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead; image_memory_barrier.oldLayout = image.layout; image_memory_barrier.newLayout = new_layout; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = image.image; image_memory_barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = image.layers; const auto stages = static_cast( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer); vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); image.layout = image_memory_barrier.newLayout; } } void GraphicsRenderDepthStencilImageBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image, vk::ImageLayout new_layout) { EXIT_IF(image.type != VulkanImageType::DepthStencil); if (new_layout == vk::ImageLayout::eUndefined || new_layout == vk::ImageLayout::ePreinitialized) { EXIT("invalid destination depth/stencil image layout: %s\n", VulkanToString(new_layout).c_str()); } if (image.layout == new_layout) { return; } vk::ImageMemoryBarrier barrier {}; barrier.sType = vk::StructureType::eImageMemoryBarrier; barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; barrier.oldLayout = image.layout; barrier.newLayout = new_layout; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image.image; barrier.subresourceRange = {ImageViewOps::DepthAspectMask(image.format), 0, VK_REMAINING_MIP_LEVELS, 0, image.layers}; const auto stages = static_cast( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer); vk_buffer.pipelineBarrier(stages, stages, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &barrier); image.layout = new_layout; } void GraphicsRenderDepthStencilBarrier(vk::CommandBuffer vk_buffer, VulkanImage& image) { EXIT_IF(image.type != VulkanImageType::DepthStencil); auto& depth = static_cast(image); if (depth.compressed) { static std::atomic log_count {0}; if (log_count.fetch_add(1, std::memory_order_relaxed) < 16) { LOGF( "DepthTexture: decompressing depth target for shader read format=%s extent=%ux%u\n", VulkanToString(depth.format).c_str(), depth.extent.width, depth.extent.height); } depth.compressed = false; } if (image.layout != vk::ImageLayout::eDepthStencilReadOnlyOptimal) { vk::ImageMemoryBarrier image_memory_barrier {}; image_memory_barrier.sType = vk::StructureType::eImageMemoryBarrier; image_memory_barrier.pNext = nullptr; image_memory_barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite; image_memory_barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; image_memory_barrier.oldLayout = image.layout; image_memory_barrier.newLayout = vk::ImageLayout::eDepthStencilReadOnlyOptimal; image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; image_memory_barrier.image = image.image; image_memory_barrier.subresourceRange.aspectMask = ImageViewOps::DepthAspectMask(image.format); image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.layerCount = image.layers; vk_buffer.pipelineBarrier( vk::PipelineStageFlagBits::eAllGraphics | vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eFragmentShader | vk::PipelineStageFlagBits::eComputeShader, vk::DependencyFlags {}, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); image.layout = image_memory_barrier.newLayout; } } void GraphicsRenderTextureBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) { EXIT_IF(buffer.IsInvalid()); Common::LockGuard lock(GetRenderContext().GetMutex()); auto vk_buffer = buffer.Handle(); auto* native = GetRenderContext().GetTextureCache().FindRenderTargetByRange(buffer, vaddr, size); if (native == nullptr) { EXIT("render-target barrier range has no cached image\n"); } GraphicsRenderTextureBarrier(vk_buffer, *native); } void GraphicsRenderDepthStencilBarrier(CommandBuffer& buffer, uint64_t vaddr, uint64_t size) { EXIT_IF(buffer.IsInvalid()); Common::LockGuard lock(GetRenderContext().GetMutex()); auto vk_buffer = buffer.Handle(); auto* native = GetRenderContext().GetTextureCache().FindDepthTargetByRange(buffer, vaddr, size); if (native == nullptr) { EXIT("depth-target barrier range has no cached image\n"); } GraphicsRenderDepthStencilBarrier(vk_buffer, *native); } } // namespace Libs::Graphics