diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 0648df922..f6b5958e1 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -691,6 +691,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::span(header); + if (rasterizer) { + rasterizer->ProcessDownloadImages(); + } event_eos->SignalFence([](void* address, u64 data, u32 num_bytes) { auto* memory = Core::Memory::Instance(); if (!memory->TryWriteBacking(address, &data, num_bytes)) { @@ -709,6 +712,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::span(header); + if (rasterizer) { + rasterizer->ProcessDownloadImages(); + } event_eop->SignalFence( [](void* address, u64 data, u32 num_bytes) { auto* memory = Core::Memory::Instance(); @@ -1137,6 +1143,9 @@ Liverpool::Task Liverpool::ProcessCompute(std::span acb, u32 vqid) { } case PM4ItOpcode::ReleaseMem: { const auto* release_mem = reinterpret_cast(header); + if (rasterizer) { + rasterizer->ProcessDownloadImages(); + } release_mem->SignalFence( [pipe_id = queue.pipe_id] { Platform::IrqC::Instance()->Signal(static_cast(pipe_id)); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 6f89bd393..7efde2c5b 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1068,6 +1068,10 @@ bool Rasterizer::ReadMemory(VAddr addr, u64 size) { return true; } +void Rasterizer::ProcessDownloadImages() { + texture_cache.ProcessDownloadImages(); +} + bool Rasterizer::IsMapped(VAddr addr, u64 size) { if (size == 0) { // There is no memory, so not mapped. diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 1820da417..416588336 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -60,6 +60,7 @@ public: u32 ReadDataFromGds(u32 gsd_offset); bool InvalidateMemory(VAddr addr, u64 size); bool ReadMemory(VAddr addr, u64 size); + void ProcessDownloadImages(); bool IsMapped(VAddr addr, u64 size); void MapMemory(VAddr addr, u64 size); void UnmapMemory(VAddr addr, u64 size); diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 7c94a0176..00509e666 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -87,18 +87,18 @@ ImageId TextureCache::GetNullImage(const vk::Format format) { void TextureCache::ProcessDownloadImages() { for (const ImageId image_id : download_images) { - DownloadImageMemory(image_id); + DownloadImageMemory(image_id, true); } download_images.clear(); } -void TextureCache::DownloadImageMemory(ImageId image_id) { +void TextureCache::DownloadImageMemory(ImageId image_id, bool sync) { Image& image = slot_images[image_id]; if (False(image.flags & ImageFlagBits::GpuModified)) { return; } auto& download_buffer = buffer_cache.GetUtilityBuffer(MemoryUsage::Download); - const u32 download_size = image.info.pitch * image.info.size.height * + const u32 download_size = image.info.pitch * image.info.size.height * image.info.size.depth * image.info.resources.layers * (image.info.num_bits / 8); ASSERT(download_size <= image.info.guest_size); const auto [download, offset] = download_buffer.Map(download_size); @@ -116,7 +116,7 @@ void TextureCache::DownloadImageMemory(ImageId image_id) { .layerCount = image.info.resources.layers, }, .imageOffset = {0, 0, 0}, - .imageExtent = {image.info.size.width, image.info.size.height, 1}, + .imageExtent = {image.info.size.width, image.info.size.height, image.info.size.depth}, }; scheduler.EndRendering(); const auto cmdbuf = scheduler.CommandBuffer(); @@ -124,11 +124,17 @@ void TextureCache::DownloadImageMemory(ImageId image_id) { cmdbuf.copyImageToBuffer(image.GetImage(), vk::ImageLayout::eTransferSrcOptimal, download_buffer.Handle(), image_download); - scheduler.DeferPriorityOperation( - [this, device_addr = image.info.guest_address, download, download_size] { - Core::Memory::Instance()->TryWriteBacking(std::bit_cast(device_addr), download, - download_size); - }); + const auto write_data = [this, device_addr = image.info.guest_address, download, + download_size] { + Core::Memory::Instance()->TryWriteBacking(std::bit_cast(device_addr), download, + download_size); + }; + if (sync) { + scheduler.Finish(); + write_data(); + } else { + scheduler.DeferPriorityOperation(write_data); + } } 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 34a8472c4..7ad29bcc6 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -272,7 +272,7 @@ private: ImageId GetNullImage(vk::Format format); /// Copies image memory back to CPU. - void DownloadImageMemory(ImageId image_id); + void DownloadImageMemory(ImageId image_id, bool sync = false); /// Thread function for copying downloaded images out to CPU memory. void DownloadedImagesThread(const std::stop_token& token);