diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 7a8f78cde1..b80af2b480 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -113,6 +113,54 @@ TextureCache

::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag } } +template +void TextureCache

::RunAllocationGarbageCollector(size_t requested_bytes) { + if (requested_bytes == 0) { + return; + } + + if (allocation_gc_frame != frame_tick) { + allocation_gc_frame = frame_tick; + allocation_gc_passes = 0; + } + if (allocation_gc_passes >= MAX_ALLOCATION_GC_PASSES_PER_FRAME) { + return; + } + + if (runtime.CanReportMemoryUsage()) { + total_used_memory = runtime.GetDeviceMemoryUsage(); + } + + const u64 request = static_cast(requested_bytes); + const u64 max_u64 = (std::numeric_limits::max)(); + const u64 projected_usage = request > (max_u64 - total_used_memory) + ? max_u64 + : total_used_memory + request; + if (projected_usage < expected_memory) { + return; + } + + RunGarbageCollector(); + ++allocation_gc_passes; + + if (runtime.CanReportMemoryUsage()) { + total_used_memory = runtime.GetDeviceMemoryUsage(); + } + + const u64 projected_after_gc = request > (max_u64 - total_used_memory) + ? max_u64 + : total_used_memory + request; + if (projected_after_gc >= critical_memory && + allocation_gc_passes < MAX_ALLOCATION_GC_PASSES_PER_FRAME) { + RunGarbageCollector(); + ++allocation_gc_passes; + + if (runtime.CanReportMemoryUsage()) { + total_used_memory = runtime.GetDeviceMemoryUsage(); + } + } +} + template void TextureCache

::RunGarbageCollector() { bool high_priority_mode = total_used_memory >= expected_memory; @@ -1606,18 +1654,20 @@ bool TextureCache

::ScaleDown(Image& image) { template ImageId TextureCache

::InsertImage(const ImageInfo& info, GPUVAddr gpu_addr, RelaxedOptions options) { + const size_t requested_size = CalculateGuestSizeInBytes(info); std::optional cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); if (!cpu_addr) { - const auto size = CalculateGuestSizeInBytes(info); - cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, size); + cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, requested_size); if (!cpu_addr) { const DAddr fake_addr = ~(1ULL << 40ULL) + virtual_invalid_space; - virtual_invalid_space += Common::AlignUp(size, 32); + virtual_invalid_space += Common::AlignUp(requested_size, 32); cpu_addr = std::optional(fake_addr); } } ASSERT_MSG(cpu_addr, "Tried to insert an image to an invalid gpu_addr=0x{:x}", gpu_addr); + RunAllocationGarbageCollector(requested_size); + const ImageId image_id = JoinImages(info, gpu_addr, *cpu_addr); const Image& image = slot_images[image_id]; // Using "image.gpu_addr" instead of "gpu_addr" is important because it might be different @@ -1634,6 +1684,8 @@ ImageId TextureCache

::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA ImageInfo new_info = info; const size_t size_bytes = CalculateGuestSizeInBytes(new_info); + RunAllocationGarbageCollector(size_bytes); + const bool broken_views = runtime.HasBrokenTextureViewFormats(); const bool native_bgr = runtime.HasNativeBgr(); join_overlap_ids.clear(); diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 0cdeb9fdc5..e2c2c5d7d9 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -120,7 +120,7 @@ class TextureCache : public VideoCommon::ChannelSetupCaches void FillImageViews(DescriptorTable& table, @@ -527,6 +529,8 @@ private: u64 modification_tick = 0; u64 frame_tick = 0; + u64 allocation_gc_frame = (std::numeric_limits::max)(); + u32 allocation_gc_passes = 0; u64 last_sampler_gc_frame = (std::numeric_limits::max)(); Common::ThreadWorker texture_decode_worker{1, "TextureDecoder"};