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_)
: 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);
}

View File

@@ -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<u64>(std::min(device_local_memory - min_vacancy_critical, min_spacing_critical),
DEFAULT_CRITICAL_GC_MEMORY));
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;
@@ -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<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) {

View File

@@ -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<DownloadedImage> 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,