From cd7268a70edb7363213785f023f7f127311ff4c0 Mon Sep 17 00:00:00 2001 From: TheTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Mon, 23 Sep 2024 18:03:42 +0300 Subject: [PATCH] video_core: Separate dirty flags and better gpu invalidation (#1034) --- src/video_core/buffer_cache/buffer_cache.cpp | 2 +- .../renderer_vulkan/vk_compute_pipeline.cpp | 2 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 2 +- src/video_core/texture_cache/image.h | 10 ++--- .../texture_cache/texture_cache.cpp | 41 +++++++++---------- src/video_core/texture_cache/texture_cache.h | 2 +- 6 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 8cbc3b947ed..caffee6ba0b 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -17,7 +17,7 @@ namespace VideoCore { static constexpr size_t NumVertexBuffers = 32; static constexpr size_t GdsBufferSize = 64_KB; static constexpr size_t StagingBufferSize = 1_GB; -static constexpr size_t UboStreamBufferSize = 128_MB; +static constexpr size_t UboStreamBufferSize = 64_MB; BufferCache::BufferCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, const AmdGpu::Liverpool* liverpool_, TextureCache& texture_cache_, diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 4fb445f66aa..3558bf78567 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -199,7 +199,7 @@ bool ComputePipeline::BindResources(VideoCore::BufferCache& buffer_cache, buffer_barriers.emplace_back(*barrier); } if (desc.is_written) { - texture_cache.MarkWritten(address, size); + texture_cache.InvalidateMemoryFromGPU(address, size); } } set_writes.push_back({ diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 29cdf761530..8edf2f50c30 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -431,7 +431,7 @@ void GraphicsPipeline::BindResources(const Liverpool::Regs& regs, buffer_barriers.emplace_back(*barrier); } if (desc.is_written) { - texture_cache.MarkWritten(address, size); + texture_cache.InvalidateMemoryFromGPU(address, size); } } set_writes.push_back({ diff --git a/src/video_core/texture_cache/image.h b/src/video_core/texture_cache/image.h index 02a48b6a182..01e6fe8f3b5 100644 --- a/src/video_core/texture_cache/image.h +++ b/src/video_core/texture_cache/image.h @@ -5,13 +5,9 @@ #include "common/enum.h" #include "common/types.h" -#include "core/libraries/videoout/buffer.h" -#include "video_core/amdgpu/liverpool.h" -#include "video_core/amdgpu/resource.h" #include "video_core/renderer_vulkan/vk_common.h" #include "video_core/texture_cache/image_info.h" #include "video_core/texture_cache/image_view.h" -#include "video_core/texture_cache/types.h" #include @@ -26,7 +22,9 @@ VK_DEFINE_HANDLE(VmaAllocator) namespace VideoCore { enum ImageFlagBits : u32 { - CpuModified = 1 << 2, ///< Contents have been modified from the CPU + CpuDirty = 1 << 1, ///< Contents have been modified from the CPU + GpuDirty = 1 << 2, ///< Contents have been modified from the GPU (valid data in buffer cache) + Dirty = CpuDirty | GpuDirty, GpuModified = 1 << 3, ///< Contents have been modified from the GPU Tracked = 1 << 4, ///< Writes and reads are being hooked from the CPU Registered = 1 << 6, ///< True when the image is registered @@ -108,7 +106,7 @@ struct Image { ImageInfo info; UniqueImage image; vk::ImageAspectFlags aspect_mask = vk::ImageAspectFlagBits::eColor; - ImageFlagBits flags = ImageFlagBits::CpuModified; + ImageFlagBits flags = ImageFlagBits::Dirty; VAddr cpu_addr = 0; VAddr cpu_addr_end = 0; std::vector image_view_infos; diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index dfa1bab6481..4813a3c5757 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -47,24 +47,23 @@ void TextureCache::InvalidateMemory(VAddr address, size_t size) { std::scoped_lock lock{mutex}; ForEachImageInRegion(address, size, [&](ImageId image_id, Image& image) { // Ensure image is reuploaded when accessed again. - image.flags |= ImageFlagBits::CpuModified; + image.flags |= ImageFlagBits::CpuDirty; // Untrack image, so the range is unprotected and the guest can write freely. UntrackImage(image_id); }); } -void TextureCache::MarkWritten(VAddr address, size_t max_size) { - static constexpr FindFlags find_flags = - FindFlags::NoCreate | FindFlags::RelaxDim | FindFlags::RelaxFmt | FindFlags::RelaxSize; - ImageInfo info{}; - info.guest_address = address; - info.guest_size_bytes = max_size; - const ImageId image_id = FindImage(info, find_flags); - if (!image_id) { - return; - } - // Ensure image is copied when accessed again. - slot_images[image_id].flags |= ImageFlagBits::CpuModified; +void TextureCache::InvalidateMemoryFromGPU(VAddr address, size_t max_size) { + std::scoped_lock lock{mutex}; + ForEachImageInRegion(address, max_size, [&](ImageId image_id, Image& image) { + // Only consider images that match base address. + // TODO: Maybe also consider subresources + if (image.info.guest_address != address) { + return; + } + // Ensure image is reuploaded when accessed again. + image.flags |= ImageFlagBits::GpuDirty; + }); } void TextureCache::UnmapMemory(VAddr cpu_addr, size_t size) { @@ -189,7 +188,7 @@ ImageId TextureCache::ExpandImage(const ImageInfo& info, ImageId image_id) { FreeImage(image_id); TrackImage(new_image_id); - new_image.flags &= ~ImageFlagBits::CpuModified; + new_image.flags &= ~ImageFlagBits::Dirty; return new_image_id; } @@ -325,7 +324,7 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info, const ImageId image_id = FindImage(image_info); Image& image = slot_images[image_id]; image.flags |= ImageFlagBits::GpuModified; - image.flags &= ~ImageFlagBits::CpuModified; + image.flags &= ~ImageFlagBits::Dirty; image.aspect_mask = vk::ImageAspectFlagBits::eDepth; const bool has_stencil = image_info.usage.stencil; @@ -362,11 +361,9 @@ ImageView& TextureCache::FindDepthTarget(const ImageInfo& image_info, } void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler /*= nullptr*/) { - if (False(image.flags & ImageFlagBits::CpuModified)) { + if (False(image.flags & ImageFlagBits::Dirty)) { return; } - // Mark image as validated. - image.flags &= ~ImageFlagBits::CpuModified; const auto& num_layers = image.info.resources.layers; const auto& num_mips = image.info.resources.levels; @@ -380,9 +377,10 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule image.info.props.is_volume ? std::max(image.info.size.depth >> m, 1u) : 1u; const auto& [mip_size, mip_pitch, mip_height, mip_ofs] = image.info.mips_layout[m]; - // Protect GPU modified resources from accidental reuploads. - if (True(image.flags & ImageFlagBits::GpuModified) && - !buffer_cache.IsRegionGpuModified(image.info.guest_address + mip_ofs, mip_size)) { + // Protect GPU modified resources from accidental CPU reuploads. + const bool is_gpu_modified = True(image.flags & ImageFlagBits::GpuModified); + const bool is_gpu_dirty = True(image.flags & ImageFlagBits::GpuDirty); + if (is_gpu_modified && !is_gpu_dirty) { const u8* addr = std::bit_cast(image.info.guest_address); const u64 hash = XXH3_64bits(addr + mip_ofs, mip_size); if (image.mip_hashes[m] == hash) { @@ -438,6 +436,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule } cmdbuf.copyBufferToImage(buffer, image.image, vk::ImageLayout::eTransferDstOptimal, image_copy); + image.flags &= ~ImageFlagBits::Dirty; } vk::Sampler TextureCache::GetSampler(const AmdGpu::Sampler& sampler) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index b2a8f13f4e9..3bbfd952c71 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -51,7 +51,7 @@ class TextureCache { void InvalidateMemory(VAddr address, size_t size); /// Marks an image as dirty if it exists at the provided address. - void MarkWritten(VAddr address, size_t max_size); + void InvalidateMemoryFromGPU(VAddr address, size_t max_size); /// Evicts any images that overlap the unmapped range. void UnmapMemory(VAddr cpu_addr, size_t size);