diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 3ff78f967..771a16f2e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -34,8 +34,9 @@ Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_, AmdGpu::Liverpool* liverpool_) : instance{instance_}, scheduler{scheduler_}, page_manager{this}, buffer_cache{instance, scheduler, liverpool_, texture_cache, page_manager}, - texture_cache{instance, scheduler, buffer_cache, page_manager}, liverpool{liverpool_}, - memory{Core::Memory::Instance()}, pipeline_cache{instance, scheduler, liverpool} { + texture_cache{instance, scheduler, liverpool_, buffer_cache, page_manager}, + liverpool{liverpool_}, memory{Core::Memory::Instance()}, + pipeline_cache{instance, scheduler, liverpool} { if (!Config::nullGpu()) { liverpool->BindRasterizer(this); } diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index f39bc16fd..f5069f3c2 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -6,6 +6,7 @@ #include "common/assert.h" #include "common/config.h" #include "common/debug.h" +#include "common/polyfill_thread.h" #include "common/scope_exit.h" #include "core/memory.h" #include "video_core/buffer_cache/buffer_cache.h" @@ -22,9 +23,10 @@ static constexpr u64 PageShift = 12; static constexpr u64 NumFramesBeforeRemoval = 32; TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, - BufferCache& buffer_cache_, PageManager& tracker_) - : instance{instance_}, scheduler{scheduler_}, buffer_cache{buffer_cache_}, tracker{tracker_}, - blit_helper{instance, scheduler}, + AmdGpu::Liverpool* liverpool_, BufferCache& buffer_cache_, + PageManager& tracker_) + : instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, + buffer_cache{buffer_cache_}, tracker{tracker_}, blit_helper{instance, scheduler}, tile_manager{instance, scheduler, buffer_cache.GetUtilityBuffer(MemoryUsage::Stream)} { // Create basic null image at fixed image ID. const auto null_id = GetNullImage(vk::Format::eR8G8B8A8Unorm); @@ -51,6 +53,9 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& std::max(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical), DEFAULT_CRITICAL_GC_MEMORY)); trigger_gc_memory = static_cast((device_local_memory - mem_threshold) / 2); + + downloaded_images_thread = + std::jthread([&](const std::stop_token& token) { DownloadedImagesThread(token); }); } TextureCache::~TextureCache() = default; @@ -121,10 +126,34 @@ void TextureCache::DownloadImageMemory(ImageId image_id) { image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}); cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, download_buffer.Handle(), image_download); - scheduler.DeferOperation([device_addr = image.info.guest_address, download, download_size] { - auto* memory = Core::Memory::Instance(); - memory->TryWriteBacking(std::bit_cast(device_addr), download, download_size); - }); + + { + std::unique_lock lock(downloaded_images_mutex); + downloaded_images_queue.emplace(scheduler.CurrentTick(), image.info.guest_address, download, + download_size); + downloaded_images_cv.notify_one(); + } +} + +void TextureCache::DownloadedImagesThread(const std::stop_token& token) { + auto* memory = Core::Memory::Instance(); + while (!token.stop_requested()) { + DownloadedImage image; + { + std::unique_lock lock{downloaded_images_mutex}; + Common::CondvarWait(downloaded_images_cv, lock, token, + [this] { return !downloaded_images_queue.empty(); }); + if (token.stop_requested()) { + break; + } + image = downloaded_images_queue.front(); + downloaded_images_queue.pop(); + } + + scheduler.GetMasterSemaphore()->Wait(image.tick); + memory->TryWriteBacking(std::bit_cast(image.device_addr), image.download, + image.download_size); + } } void TextureCache::MarkAsMaybeDirty(ImageId image_id, Image& image) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 99b5ea971..6edbadbf9 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -17,6 +17,10 @@ #include "video_core/texture_cache/sampler.h" #include "video_core/texture_cache/tile_manager.h" +namespace AmdGpu { +struct Liverpool; +} + namespace VideoCore { class BufferCache; @@ -85,7 +89,7 @@ public: public: TextureCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, - BufferCache& buffer_cache, PageManager& tracker); + AmdGpu::Liverpool* liverpool, BufferCache& buffer_cache, PageManager& tracker); ~TextureCache(); TileManager& GetTileManager() noexcept { @@ -272,6 +276,9 @@ private: /// Copies image memory back to CPU. void DownloadImageMemory(ImageId image_id); + /// Thread function for copying downloaded images out to CPU memory. + void DownloadedImagesThread(const std::stop_token& token); + /// Create an image from the given parameters [[nodiscard]] ImageId InsertImage(const ImageInfo& info, VAddr cpu_addr); @@ -308,6 +315,7 @@ private: private: const Vulkan::Instance& instance; Vulkan::Scheduler& scheduler; + AmdGpu::Liverpool* liverpool; BufferCache& buffer_cache; PageManager& tracker; BlitHelper blit_helper; @@ -326,6 +334,17 @@ private: PageTable page_table; std::mutex mutex; + struct DownloadedImage { + u64 tick; + VAddr device_addr; + void* download; + size_t download_size; + }; + std::queue downloaded_images_queue; + std::mutex downloaded_images_mutex; + std::condition_variable_any downloaded_images_cv; + std::jthread downloaded_images_thread; + struct MetaDataInfo { enum class Type { CMask,