mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 22:10:49 +00:00
Some changes to GC
This commit is contained in:
@@ -22,6 +22,7 @@ add_library(video_core STATIC
|
||||
buffer_cache/usage_tracker.h
|
||||
buffer_cache/virtual_range_cache.h
|
||||
buffer_cache/word_manager.h
|
||||
cache_reclaim.h
|
||||
cache_types.h
|
||||
capture.h
|
||||
cdma_pusher.cpp
|
||||
|
||||
@@ -30,34 +30,52 @@ BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R
|
||||
#ifdef YUZU_LEGACY
|
||||
immediately_free = (Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Aggressive);
|
||||
#endif
|
||||
if (!runtime.CanReportMemoryUsage()) {
|
||||
minimum_memory = DEFAULT_EXPECTED_MEMORY;
|
||||
critical_memory = DEFAULT_CRITICAL_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
const s64 device_local_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
|
||||
const s64 min_spacing_expected = device_local_memory - 1_GiB;
|
||||
const s64 min_spacing_critical = device_local_memory - 512_MiB;
|
||||
const s64 mem_threshold = (std::min)(device_local_memory, TARGET_THRESHOLD);
|
||||
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
|
||||
const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
|
||||
minimum_memory = static_cast<u64>(
|
||||
(std::max)((std::min)(device_local_memory - min_vacancy_expected, min_spacing_expected),
|
||||
DEFAULT_EXPECTED_MEMORY));
|
||||
critical_memory = static_cast<u64>(
|
||||
(std::max)((std::min)(device_local_memory - min_vacancy_critical, min_spacing_critical),
|
||||
DEFAULT_CRITICAL_MEMORY));
|
||||
device_local_memory = runtime.GetDeviceLocalMemory();
|
||||
const auto thresholds = VideoCommon::MakeReclaimThresholds(
|
||||
device_local_memory, static_cast<u64>(TARGET_THRESHOLD),
|
||||
static_cast<u64>(DEFAULT_EXPECTED_MEMORY), static_cast<u64>(DEFAULT_CRITICAL_MEMORY));
|
||||
minimum_memory = thresholds.minimum;
|
||||
expected_memory = thresholds.expected;
|
||||
critical_memory = thresholds.critical;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
BufferCache<P>::~BufferCache() = default;
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::ReclaimInline() {
|
||||
if (total_used_memory < minimum_memory) {
|
||||
return;
|
||||
}
|
||||
int num_iterations = 8;
|
||||
const auto clean_up = [this, &num_iterations](BufferId buffer_id) {
|
||||
if (num_iterations == 0) {
|
||||
return true;
|
||||
}
|
||||
Buffer& buffer = slot_buffers[buffer_id];
|
||||
if (memory_tracker.IsRegionGpuModified(buffer.CpuAddr(), buffer.SizeBytes())) {
|
||||
return false;
|
||||
}
|
||||
--num_iterations;
|
||||
DeleteBuffer(buffer_id);
|
||||
return false;
|
||||
};
|
||||
lru_cache.ForEachItemBelow(frame_tick - INLINE_TICKS_TO_DESTROY, clean_up);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::RunGarbageCollector() {
|
||||
const bool aggressive_gc = total_used_memory >= critical_memory;
|
||||
const u64 ticks_to_destroy = aggressive_gc ? 60 : 120;
|
||||
int num_iterations = aggressive_gc ? 64 : 32;
|
||||
const bool aggressive_gc = heap_pressure || total_used_memory >= critical_memory;
|
||||
const bool priority_gc = aggressive_gc || total_used_memory >= expected_memory;
|
||||
u64 ticks_to_destroy = 120;
|
||||
int num_iterations = 32;
|
||||
if (aggressive_gc) {
|
||||
ticks_to_destroy = 30;
|
||||
num_iterations = 64;
|
||||
} else if (priority_gc) {
|
||||
ticks_to_destroy = 60;
|
||||
num_iterations = 48;
|
||||
}
|
||||
const auto clean_up = [this, &num_iterations](BufferId buffer_id) {
|
||||
if (num_iterations == 0) {
|
||||
return true;
|
||||
@@ -96,11 +114,12 @@ void BufferCache<P>::TickFrame() {
|
||||
const bool skip_preferred = hits * 256 < shots * 251;
|
||||
channel_state->uniform_buffer_skip_cache_size = skip_preferred ? DEFAULT_SKIP_CACHE_SIZE : 0;
|
||||
|
||||
// If we can obtain the memory info, use it instead of the estimate.
|
||||
if (runtime.CanReportMemoryUsage()) {
|
||||
total_used_memory = runtime.GetDeviceMemoryUsage();
|
||||
heap_pressure = false;
|
||||
if (device_local_memory != 0 && runtime.CanReportMemoryUsage()) {
|
||||
heap_pressure = runtime.GetDeviceMemoryUsage() + HEAP_PRESSURE_HEADROOM >=
|
||||
device_local_memory;
|
||||
}
|
||||
if (total_used_memory >= minimum_memory) {
|
||||
if (total_used_memory >= minimum_memory || heap_pressure) {
|
||||
RunGarbageCollector();
|
||||
}
|
||||
++frame_tick;
|
||||
@@ -1674,6 +1693,7 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
|
||||
template <class P>
|
||||
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size,
|
||||
bool sparse_compatible) {
|
||||
ReclaimInline();
|
||||
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
|
||||
device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
|
||||
wanted_size = static_cast<u32>(device_addr_end - device_addr);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "video_core/buffer_cache/buffer_base.h"
|
||||
#include "video_core/buffer_cache/virtual_range_cache.h"
|
||||
#include "video_core/control/channel_state_cache.h"
|
||||
#include "video_core/cache_reclaim.h"
|
||||
#include "video_core/delayed_destruction_ring.h"
|
||||
#include "video_core/dirty_flags.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
@@ -199,6 +200,8 @@ class BufferCache : public VideoCommon::ChannelSetupCaches<BufferCacheChannelInf
|
||||
|
||||
static constexpr s64 DEFAULT_EXPECTED_MEMORY = 512_MiB;
|
||||
static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB;
|
||||
static constexpr u64 HEAP_PRESSURE_HEADROOM = 512_MiB;
|
||||
static constexpr u64 INLINE_TICKS_TO_DESTROY = 240;
|
||||
|
||||
// Debug Flags.
|
||||
|
||||
@@ -381,6 +384,8 @@ private:
|
||||
|
||||
void RunGarbageCollector();
|
||||
|
||||
void ReclaimInline();
|
||||
|
||||
void BindHostIndexBuffer();
|
||||
|
||||
void BindHostVertexBuffers();
|
||||
@@ -540,8 +545,11 @@ private:
|
||||
std::vector<MultiRangeSegment> compute_segments;
|
||||
u64 frame_tick = 0;
|
||||
u64 total_used_memory = 0;
|
||||
u64 device_local_memory = 0;
|
||||
u64 minimum_memory = 0;
|
||||
u64 expected_memory = 0;
|
||||
u64 critical_memory = 0;
|
||||
bool heap_pressure = false;
|
||||
BufferId inline_buffer_id;
|
||||
#ifdef YUZU_LEGACY
|
||||
bool immediately_free = false;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace VideoCommon {
|
||||
|
||||
struct ReclaimThresholds {
|
||||
u64 minimum{};
|
||||
u64 expected{};
|
||||
u64 critical{};
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr ReclaimThresholds MakeReclaimThresholds(u64 device_local_memory,
|
||||
u64 target_threshold,
|
||||
u64 default_expected,
|
||||
u64 default_critical) {
|
||||
u64 critical = default_critical;
|
||||
if (device_local_memory != 0) {
|
||||
const u64 budget = (std::min)(device_local_memory, target_threshold);
|
||||
critical = (std::min)(critical, budget / 2);
|
||||
}
|
||||
const u64 expected = (std::min)(default_expected, (critical * 3) / 4);
|
||||
return ReclaimThresholds{
|
||||
.minimum = (expected * 3) / 4,
|
||||
.expected = expected,
|
||||
.critical = critical,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace VideoCommon
|
||||
@@ -58,24 +58,14 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
|
||||
void(slot_samplers.insert(runtime, sampler_descriptor));
|
||||
|
||||
if constexpr (HAS_DEVICE_MEMORY_INFO) {
|
||||
const s64 device_local_memory = static_cast<s64>(runtime.GetDeviceLocalMemory());
|
||||
const s64 min_spacing_expected = device_local_memory - 1_GiB;
|
||||
const s64 min_spacing_critical = device_local_memory - 512_MiB;
|
||||
const s64 mem_threshold = (std::min)(device_local_memory, TARGET_THRESHOLD);
|
||||
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
|
||||
const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
|
||||
expected_memory = static_cast<u64>(
|
||||
(std::max)((std::min)(device_local_memory - min_vacancy_expected, min_spacing_expected),
|
||||
DEFAULT_EXPECTED_MEMORY));
|
||||
critical_memory = static_cast<u64>(
|
||||
(std::max)((std::min)(device_local_memory - min_vacancy_critical, min_spacing_critical),
|
||||
DEFAULT_CRITICAL_MEMORY));
|
||||
minimum_memory = static_cast<u64>((device_local_memory - mem_threshold) / 2);
|
||||
} else {
|
||||
expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB;
|
||||
critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB;
|
||||
minimum_memory = 0;
|
||||
device_local_memory = runtime.GetDeviceLocalMemory();
|
||||
}
|
||||
const auto thresholds = VideoCommon::MakeReclaimThresholds(
|
||||
device_local_memory, static_cast<u64>(TARGET_THRESHOLD),
|
||||
static_cast<u64>(DEFAULT_EXPECTED_MEMORY), static_cast<u64>(DEFAULT_CRITICAL_MEMORY));
|
||||
minimum_memory = thresholds.minimum;
|
||||
expected_memory = thresholds.expected;
|
||||
critical_memory = thresholds.critical;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
@@ -85,8 +75,9 @@ void TextureCache<P>::RunGarbageCollector() {
|
||||
u64 ticks_to_destroy = 0;
|
||||
size_t num_iterations = 0;
|
||||
const auto Configure = [&](bool allow_aggressive) {
|
||||
high_priority_mode = total_used_memory >= expected_memory;
|
||||
aggressive_mode = allow_aggressive && total_used_memory >= critical_memory;
|
||||
high_priority_mode = heap_pressure || total_used_memory >= expected_memory;
|
||||
aggressive_mode =
|
||||
allow_aggressive && (heap_pressure || total_used_memory >= critical_memory);
|
||||
ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL;
|
||||
num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10);
|
||||
};
|
||||
@@ -100,7 +91,7 @@ void TextureCache<P>::RunGarbageCollector() {
|
||||
return false;
|
||||
}
|
||||
const bool must_download = IsDownloadable(image) && False(image.flags & ImageFlagBits::BadOverlap);
|
||||
if ((!aggressive_mode && True(image.flags & ImageFlagBits::CostlyLoad)) || (!high_priority_mode && must_download)) {
|
||||
if (!aggressive_mode && (must_download || True(image.flags & ImageFlagBits::CostlyLoad))) {
|
||||
return false;
|
||||
}
|
||||
if (must_download) {
|
||||
@@ -126,7 +117,7 @@ void TextureCache<P>::RunGarbageCollector() {
|
||||
};
|
||||
Configure(false);
|
||||
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
|
||||
if (total_used_memory >= critical_memory) {
|
||||
if (heap_pressure || total_used_memory >= critical_memory) {
|
||||
Configure(true);
|
||||
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, Cleanup);
|
||||
}
|
||||
@@ -134,11 +125,12 @@ void TextureCache<P>::RunGarbageCollector() {
|
||||
|
||||
template <class P>
|
||||
void TextureCache<P>::TickFrame() {
|
||||
// If we can obtain the memory info, use it instead of the estimate.
|
||||
if (runtime.CanReportMemoryUsage()) {
|
||||
total_used_memory = runtime.GetDeviceMemoryUsage();
|
||||
heap_pressure = false;
|
||||
if (device_local_memory != 0 && runtime.CanReportMemoryUsage()) {
|
||||
heap_pressure = runtime.GetDeviceMemoryUsage() + HEAP_PRESSURE_HEADROOM >=
|
||||
device_local_memory;
|
||||
}
|
||||
if (total_used_memory > minimum_memory) {
|
||||
if (total_used_memory > minimum_memory || heap_pressure) {
|
||||
RunGarbageCollector();
|
||||
}
|
||||
sentenced_images.Tick();
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "common/thread_worker.h"
|
||||
#include "video_core/compatible_formats.h"
|
||||
#include "video_core/control/channel_state_cache.h"
|
||||
#include "video_core/cache_reclaim.h"
|
||||
#include "video_core/delayed_destruction_ring.h"
|
||||
#include "video_core/engines/fermi_2d.h"
|
||||
#include "video_core/surface.h"
|
||||
@@ -121,6 +122,7 @@ class TextureCache : public VideoCommon::ChannelSetupCaches<TextureCacheChannelI
|
||||
|
||||
static constexpr s64 DEFAULT_EXPECTED_MEMORY = 1_GiB + 125_MiB;
|
||||
static constexpr s64 DEFAULT_CRITICAL_MEMORY = 1_GiB + 625_MiB;
|
||||
static constexpr u64 HEAP_PRESSURE_HEADROOM = 512_MiB;
|
||||
static constexpr size_t GC_EMERGENCY_COUNTS = 2;
|
||||
|
||||
using Runtime = typename P::Runtime;
|
||||
@@ -440,9 +442,11 @@ private:
|
||||
bool has_deleted_images = false;
|
||||
bool is_rescaling = false;
|
||||
u64 total_used_memory = 0;
|
||||
u64 minimum_memory;
|
||||
u64 expected_memory;
|
||||
u64 critical_memory;
|
||||
u64 device_local_memory = 0;
|
||||
u64 minimum_memory = 0;
|
||||
u64 expected_memory = 0;
|
||||
u64 critical_memory = 0;
|
||||
bool heap_pressure = false;
|
||||
|
||||
struct BufferDownload {
|
||||
GPUVAddr address;
|
||||
|
||||
Reference in New Issue
Block a user