#include "graphics/host_gpu/renderer/cache/gpuResourceManager.h" #include "common/assert.h" #include "graphics/guest_gpu/command_processor/commandProcessor.h" #include "graphics/guest_gpu/graphicsRun.h" #include "graphics/host_gpu/renderer/commandScheduler.h" namespace Libs::Graphics { GpuResourceManager::GpuResourceManager(GraphicContext& graphics, CommandScheduler& scheduler) : m_scheduler(scheduler), m_buffer_cache(graphics, scheduler, m_page_manager, m_texture_cache, m_resource_mutex), m_texture_cache(graphics, scheduler, m_page_manager, m_buffer_cache, m_resource_mutex) {} GpuResourceManager::~GpuResourceManager() = default; bool GpuResourceManager::HandleFault(PageFaultAccess access, uint64_t fault_vaddr) noexcept { constexpr uint64_t fault_size = 8; if (!IsMapped(fault_vaddr, fault_size)) { return false; } if (CommandScheduler::InDeferredOperation()) { EXIT("unsupported guest-memory fault from an asynchronous GPU completion, " "addr=0x%016" PRIx64 " access=%u\n", fault_vaddr, static_cast(access)); } bool handled = false; const auto resolve = [this, access, fault_vaddr, &handled](CommandProcessor& cp) { cp.BeginReadbackTransaction(); { ResourceMutex::FaultScope fault(m_resource_mutex); if (access == PageFaultAccess::Write) { m_buffer_cache.InvalidateMemory(fault_vaddr, fault_size); m_texture_cache.InvalidateMemory(fault_vaddr, fault_size); } else { m_buffer_cache.ReadMemory(fault_vaddr, fault_size); } handled = true; } cp.EndReadbackTransaction(); }; if (auto* cp = Gpu::CurrentCommandProcessor(); cp != nullptr) { resolve(*cp); return handled; } if (m_resource_mutex.IsOwnedByCurrentThread()) { EXIT("unsupported page fault from a pre-owned resource transaction, addr=0x%016" PRIx64 " access=%u\n", fault_vaddr, static_cast(access)); } EXIT_IF(m_gpu == nullptr); m_gpu->SendCommandSyncWithProcessor(resolve); return handled; } bool GpuResourceManager::InvalidateMemory(uint64_t vaddr, uint64_t size) { if (!IsMapped(vaddr, size)) { return false; } if (CommandScheduler::InDeferredOperation()) { EXIT("unsupported memory invalidation from an asynchronous GPU completion, " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", vaddr, size); } const auto resolve = [this, vaddr, size](CommandProcessor& cp) { cp.BeginReadbackTransaction(); { ResourceMutex::FaultScope fault(m_resource_mutex); m_buffer_cache.InvalidateMemory(vaddr, size); m_texture_cache.InvalidateMemory(vaddr, size); } cp.EndReadbackTransaction(); }; if (auto* cp = Gpu::CurrentCommandProcessor(); cp != nullptr) { resolve(*cp); return true; } if (m_resource_mutex.IsOwnedByCurrentThread()) { EXIT("unsupported memory invalidation from a pre-owned resource transaction, " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", vaddr, size); } EXIT_IF(m_gpu == nullptr); m_gpu->SendCommandSyncWithProcessor(resolve); return true; } bool GpuResourceManager::IsMapped(uint64_t vaddr, uint64_t size) const noexcept { if (vaddr == 0 || size == 0 || vaddr >= TRACKER_ADDRESS_SIZE || size > TRACKER_ADDRESS_SIZE - vaddr) { return false; } std::shared_lock lock(m_mapped_ranges_mutex); return m_mapped_ranges.Contains(vaddr, size); } void GpuResourceManager::MapMemory(uint64_t vaddr, uint64_t size) { { std::lock_guard lock(m_mapped_ranges_mutex); m_mapped_ranges.Add(vaddr, size); } m_page_manager.OnGpuMap(vaddr, size); } void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size) { if (CommandScheduler::InDeferredOperation()) { EXIT("unsupported memory unmap from an asynchronous GPU completion, " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", vaddr, size); } if (m_resource_mutex.IsOwnedByCurrentThread()) { EXIT("unsupported memory unmap from a pre-owned resource transaction, " "addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", vaddr, size); } const auto unmap = [this, vaddr, size] { if (m_scheduler.Active()) { const auto tick = m_scheduler.CurrentTick(); m_scheduler.FinishCurrent(); m_scheduler.WaitPriorityOperations(tick); } m_buffer_cache.UnmapMemory(vaddr, size); m_texture_cache.UnmapMemory(vaddr, size); m_page_manager.OnGpuUnmap(vaddr, size); std::lock_guard lock(m_mapped_ranges_mutex); m_mapped_ranges.Subtract(vaddr, size); }; if (m_gpu == nullptr) { unmap(); return; } m_gpu->SendCommandSync(unmap); } void GpuResourceManager::RunGarbageCollector() { m_texture_cache.ProcessDownloadImages(); m_texture_cache.RunGarbageCollector(); m_buffer_cache.RunGarbageCollector(); } } // namespace Libs::Graphics