texture_cache: Make sure that readback images are downloaded in time (#3593)

This commit is contained in:
squidbus
2025-09-13 14:43:38 -07:00
committed by GitHub
parent e402ea3de4
commit c51abe4e8b
3 changed files with 59 additions and 10 deletions

View File

@@ -34,8 +34,9 @@ Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_,
AmdGpu::Liverpool* liverpool_) AmdGpu::Liverpool* liverpool_)
: instance{instance_}, scheduler{scheduler_}, page_manager{this}, : instance{instance_}, scheduler{scheduler_}, page_manager{this},
buffer_cache{instance, scheduler, liverpool_, texture_cache, page_manager}, buffer_cache{instance, scheduler, liverpool_, texture_cache, page_manager},
texture_cache{instance, scheduler, buffer_cache, page_manager}, liverpool{liverpool_}, texture_cache{instance, scheduler, liverpool_, buffer_cache, page_manager},
memory{Core::Memory::Instance()}, pipeline_cache{instance, scheduler, liverpool} { liverpool{liverpool_}, memory{Core::Memory::Instance()},
pipeline_cache{instance, scheduler, liverpool} {
if (!Config::nullGpu()) { if (!Config::nullGpu()) {
liverpool->BindRasterizer(this); liverpool->BindRasterizer(this);
} }

View File

@@ -6,6 +6,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h" #include "common/config.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/polyfill_thread.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "core/memory.h" #include "core/memory.h"
#include "video_core/buffer_cache/buffer_cache.h" #include "video_core/buffer_cache/buffer_cache.h"
@@ -22,9 +23,10 @@ static constexpr u64 PageShift = 12;
static constexpr u64 NumFramesBeforeRemoval = 32; static constexpr u64 NumFramesBeforeRemoval = 32;
TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
BufferCache& buffer_cache_, PageManager& tracker_) AmdGpu::Liverpool* liverpool_, BufferCache& buffer_cache_,
: instance{instance_}, scheduler{scheduler_}, buffer_cache{buffer_cache_}, tracker{tracker_}, PageManager& tracker_)
blit_helper{instance, scheduler}, : 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)} { tile_manager{instance, scheduler, buffer_cache.GetUtilityBuffer(MemoryUsage::Stream)} {
// Create basic null image at fixed image ID. // Create basic null image at fixed image ID.
const auto null_id = GetNullImage(vk::Format::eR8G8B8A8Unorm); const auto null_id = GetNullImage(vk::Format::eR8G8B8A8Unorm);
@@ -51,6 +53,9 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
std::max<u64>(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical), std::max<u64>(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical),
DEFAULT_CRITICAL_GC_MEMORY)); DEFAULT_CRITICAL_GC_MEMORY));
trigger_gc_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2); trigger_gc_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2);
downloaded_images_thread =
std::jthread([&](const std::stop_token& token) { DownloadedImagesThread(token); });
} }
TextureCache::~TextureCache() = default; TextureCache::~TextureCache() = default;
@@ -121,10 +126,34 @@ void TextureCache::DownloadImageMemory(ImageId image_id) {
image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {}); image.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead, {});
cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal, cmdbuf.copyImageToBuffer(image.image, vk::ImageLayout::eTransferSrcOptimal,
download_buffer.Handle(), image_download); 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<u8*>(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<u8*>(image.device_addr), image.download,
image.download_size);
}
} }
void TextureCache::MarkAsMaybeDirty(ImageId image_id, Image& image) { void TextureCache::MarkAsMaybeDirty(ImageId image_id, Image& image) {

View File

@@ -17,6 +17,10 @@
#include "video_core/texture_cache/sampler.h" #include "video_core/texture_cache/sampler.h"
#include "video_core/texture_cache/tile_manager.h" #include "video_core/texture_cache/tile_manager.h"
namespace AmdGpu {
struct Liverpool;
}
namespace VideoCore { namespace VideoCore {
class BufferCache; class BufferCache;
@@ -85,7 +89,7 @@ public:
public: public:
TextureCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, TextureCache(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
BufferCache& buffer_cache, PageManager& tracker); AmdGpu::Liverpool* liverpool, BufferCache& buffer_cache, PageManager& tracker);
~TextureCache(); ~TextureCache();
TileManager& GetTileManager() noexcept { TileManager& GetTileManager() noexcept {
@@ -272,6 +276,9 @@ private:
/// Copies image memory back to CPU. /// Copies image memory back to CPU.
void DownloadImageMemory(ImageId image_id); 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 /// Create an image from the given parameters
[[nodiscard]] ImageId InsertImage(const ImageInfo& info, VAddr cpu_addr); [[nodiscard]] ImageId InsertImage(const ImageInfo& info, VAddr cpu_addr);
@@ -308,6 +315,7 @@ private:
private: private:
const Vulkan::Instance& instance; const Vulkan::Instance& instance;
Vulkan::Scheduler& scheduler; Vulkan::Scheduler& scheduler;
AmdGpu::Liverpool* liverpool;
BufferCache& buffer_cache; BufferCache& buffer_cache;
PageManager& tracker; PageManager& tracker;
BlitHelper blit_helper; BlitHelper blit_helper;
@@ -326,6 +334,17 @@ private:
PageTable page_table; PageTable page_table;
std::mutex mutex; std::mutex mutex;
struct DownloadedImage {
u64 tick;
VAddr device_addr;
void* download;
size_t download_size;
};
std::queue<DownloadedImage> downloaded_images_queue;
std::mutex downloaded_images_mutex;
std::condition_variable_any downloaded_images_cv;
std::jthread downloaded_images_thread;
struct MetaDataInfo { struct MetaDataInfo {
enum class Type { enum class Type {
CMask, CMask,