From 3fbee093b2bf3b4c15dbc5bb48a3bc768ecedbc9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 12 Mar 2023 21:43:31 +0100 Subject: TextureCache: refactor DMA downloads to allow multiple buffers. --- src/video_core/renderer_opengl/gl_rasterizer.cpp | 2 +- .../renderer_opengl/gl_texture_cache.cpp | 41 ++++++++++++--------- src/video_core/renderer_opengl/gl_texture_cache.h | 3 +- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 2 +- .../renderer_vulkan/vk_texture_cache.cpp | 43 ++++++++++++++-------- src/video_core/renderer_vulkan/vk_texture_cache.h | 7 ++-- src/video_core/texture_cache/texture_cache.h | 12 +++++- src/video_core/texture_cache/texture_cache_base.h | 6 ++- 8 files changed, 75 insertions(+), 41 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 90e35e307..2de533584 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1299,7 +1299,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, if constexpr (IS_IMAGE_UPLOAD) { image->UploadMemory(buffer->Handle(), offset, copy_span); } else { - image->DownloadMemory(buffer->Handle(), offset, copy_span); + texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span); } return true; } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 0b9c4a904..670d8cafd 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -801,32 +801,34 @@ void Image::UploadMemory(const ImageBufferMap& map, UploadMemory(map.buffer, map.offset, copies); } -void Image::DownloadMemory(GLuint buffer_handle, size_t buffer_offset, +void Image::DownloadMemory(std::span buffer_handles, size_t buffer_offset, std::span copies) { const bool is_rescaled = True(flags & ImageFlagBits::Rescaled); if (is_rescaled) { ScaleDown(); } glMemoryBarrier(GL_PIXEL_BUFFER_BARRIER_BIT); // TODO: Move this to its own API - glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_handle); - glPixelStorei(GL_PACK_ALIGNMENT, 1); + for (auto buffer_handle : buffer_handles) { + glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer_handle); + glPixelStorei(GL_PACK_ALIGNMENT, 1); - u32 current_row_length = std::numeric_limits::max(); - u32 current_image_height = std::numeric_limits::max(); + u32 current_row_length = std::numeric_limits::max(); + u32 current_image_height = std::numeric_limits::max(); - for (const VideoCommon::BufferImageCopy& copy : copies) { - if (copy.image_subresource.base_level >= gl_num_levels) { - continue; - } - if (current_row_length != copy.buffer_row_length) { - current_row_length = copy.buffer_row_length; - glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length); - } - if (current_image_height != copy.buffer_image_height) { - current_image_height = copy.buffer_image_height; - glPixelStorei(GL_PACK_IMAGE_HEIGHT, current_image_height); + for (const VideoCommon::BufferImageCopy& copy : copies) { + if (copy.image_subresource.base_level >= gl_num_levels) { + continue; + } + if (current_row_length != copy.buffer_row_length) { + current_row_length = copy.buffer_row_length; + glPixelStorei(GL_PACK_ROW_LENGTH, current_row_length); + } + if (current_image_height != copy.buffer_image_height) { + current_image_height = copy.buffer_image_height; + glPixelStorei(GL_PACK_IMAGE_HEIGHT, current_image_height); + } + CopyImageToBuffer(copy, buffer_offset); } - CopyImageToBuffer(copy, buffer_offset); } if (is_rescaled) { ScaleUp(true); @@ -835,7 +837,10 @@ void Image::DownloadMemory(GLuint buffer_handle, size_t buffer_offset, void Image::DownloadMemory(ImageBufferMap& map, std::span copies) { - DownloadMemory(map.buffer, map.offset, copies); + std::array buffers{ + map.buffer, + }; + DownloadMemory(buffers, map.offset, copies); } GLuint Image::StorageHandle() noexcept { diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 911e4607a..67d6910b4 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -212,7 +212,7 @@ public: void UploadMemory(const ImageBufferMap& map, std::span copies); - void DownloadMemory(GLuint buffer_handle, size_t buffer_offset, + void DownloadMemory(std::span buffer_handle, size_t buffer_offset, std::span copies); void DownloadMemory(ImageBufferMap& map, std::span copies); @@ -376,6 +376,7 @@ struct TextureCacheParams { using Sampler = OpenGL::Sampler; using Framebuffer = OpenGL::Framebuffer; using AsyncBuffer = u32; + using BufferType = GLuint; }; using TextureCache = VideoCommon::TextureCache; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 673ab478e..8fc783cc0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -793,7 +793,7 @@ bool AccelerateDMA::DmaBufferImageCopy(const Tegra::DMA::ImageCopy& copy_info, if constexpr (IS_IMAGE_UPLOAD) { image->UploadMemory(buffer->Handle(), offset, copy_span); } else { - image->DownloadMemory(buffer->Handle(), offset, copy_span); + texture_cache.DownloadImageIntoBuffer(image, buffer->Handle(), offset, copy_span); } return true; } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index ae15f6976..e4d077e63 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1,10 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later #include #include #include #include +#include #include "common/bit_cast.h" #include "common/bit_util.h" @@ -1341,16 +1342,20 @@ void Image::UploadMemory(const StagingBufferRef& map, std::span buffers_span, VkDeviceSize offset, std::span copies) { const bool is_rescaled = True(flags & ImageFlagBits::Rescaled); if (is_rescaled) { ScaleDown(); } + boost::container::small_vector buffers_vector{}; + for (auto& buffer : buffers_span) { + buffers_vector.push_back(buffer); + } std::vector vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); scheduler->RequestOutsideRenderPassOperationContext(); - scheduler->Record([buffer, image = *original_image, aspect_mask = aspect_mask, - vk_copies](vk::CommandBuffer cmdbuf) { + scheduler->Record([buffers = std::move(buffers_vector), image = *original_image, + aspect_mask = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { const VkImageMemoryBarrier read_barrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, @@ -1369,6 +1374,20 @@ void Image::DownloadMemory(VkBuffer buffer, VkDeviceSize offset, .layerCount = VK_REMAINING_ARRAY_LAYERS, }, }; + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, read_barrier); + + for (auto buffer : buffers) { + cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, + vk_copies); + } + + const VkMemoryBarrier memory_write_barrier{ + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, + }; const VkImageMemoryBarrier image_write_barrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, @@ -1387,15 +1406,6 @@ void Image::DownloadMemory(VkBuffer buffer, VkDeviceSize offset, .layerCount = VK_REMAINING_ARRAY_LAYERS, }, }; - const VkMemoryBarrier memory_write_barrier{ - .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, - }; - cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, read_barrier); - cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, vk_copies); cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, memory_write_barrier, nullptr, image_write_barrier); }); @@ -1405,7 +1415,10 @@ void Image::DownloadMemory(VkBuffer buffer, VkDeviceSize offset, } void Image::DownloadMemory(const StagingBufferRef& map, std::span copies) { - DownloadMemory(map.buffer, map.offset, copies); + std::array buffers{ + map.buffer, + }; + DownloadMemory(buffers, map.offset, copies); } bool Image::IsRescaled() const noexcept { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index d5ee23f8d..422476188 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -138,7 +138,7 @@ public: void UploadMemory(const StagingBufferRef& map, std::span copies); - void DownloadMemory(VkBuffer buffer, VkDeviceSize offset, + void DownloadMemory(std::span buffers, VkDeviceSize offset, std::span copies); void DownloadMemory(const StagingBufferRef& map, @@ -371,6 +371,7 @@ struct TextureCacheParams { using Sampler = Vulkan::Sampler; using Framebuffer = Vulkan::Framebuffer; using AsyncBuffer = Vulkan::StagingBufferRef; + using BufferType = VkBuffer; }; using TextureCache = VideoCommon::TextureCache; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index ed5c768d8..2cd5aa31e 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -833,6 +833,16 @@ std::pair::Image*, BufferImageCopy> TextureCache

::Dm return {image, copy}; } +template +void TextureCache

::DownloadImageIntoBuffer( + typename TextureCache

::Image* image, typename TextureCache

::BufferType buffer, + size_t buffer_offset, std::span copies) { + std::array buffers{ + buffer, + }; + image->DownloadMemory(buffers, buffer_offset, copies); +} + template void TextureCache

::RefreshContents(Image& image, ImageId image_id) { if (False(image.flags & ImageFlagBits::CpuModified)) { diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 5a5b4179c..51f44aed5 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 yuzu Emulator Project +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -119,6 +119,7 @@ class TextureCache : public VideoCommon::ChannelSetupCaches copies); + /// Return true when a CPU region is modified from the GPU [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); -- cgit v1.2.3