aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/texture_cache/texture_cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/texture_cache/texture_cache.h')
-rw-r--r--src/video_core/texture_cache/texture_cache.h74
1 files changed, 52 insertions, 22 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 63abffed0f..c8aaf8dff5 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -225,19 +225,24 @@ void TextureCache<P>::TickFrame() {
// VRAM (another game: 7.0 -> 6.4 GB), and collecting only past it means the driver pages
// textures out. It is also the room to use: Eden's device memory figure is capped near
// 7 GB, which on a 12 GB card (11.2 GB budget) kept title 1 evicting textures with 3 GB
- // unused. EDEN_NX2_TC_*_MIB overrides still win.
+ // unused. Both thresholds stay under it with a margin (1/8 of it, at most 1 GiB): past it
+ // allocations fail and images end up unbacked (garbage textures), and Windows shrinks the
+ // budget as the card fills (16 GB card: 13.5 GB left mid-race), hence the re-read every 30
+ // frames. EDEN_NX2_TC_*_MIB overrides still win.
if constexpr (requires { runtime.GetDeviceMemoryBudget(); }) {
- if (native_thresholds_applied && budget_check_frames++ % 60 == 0) {
+ if (native_thresholds_applied && budget_check_frames++ % 30 == 0) {
const u64 budget = runtime.GetDeviceMemoryBudget();
if (budget > 2_GiB) {
const u64 old_critical = critical_memory;
- critical_memory = budget - 768_MiB;
- expected_memory = budget - 1536_MiB;
- // Log only real changes (the budget moves by a few MiB all the time).
+ const u64 margin = (std::min)(budget / 8, 1_GiB);
+ critical_memory = budget - margin;
+ expected_memory = budget - 2 * margin;
+ // Log the first values and real changes (the budget moves by a few MiB all
+ // the time).
const u64 change = critical_memory > old_critical
? critical_memory - old_critical
: old_critical - critical_memory;
- ApplyThresholdOverrides(change >= 256_MiB);
+ ApplyThresholdOverrides(budget_check_frames == 1 || change >= 256_MiB);
}
}
}
@@ -1434,7 +1439,8 @@ void TextureCache<P>::RefreshSparseLayers(Image& image) {
}
}
image.dirty_layers.clear();
- const std::vector<u32> bound = layers.empty() ? std::vector<u32>{} : image.BindLayers(layers);
+ const std::vector<u32> bound =
+ layers.empty() ? std::vector<u32>{} : BindSparseLayers(image, layers);
if (bound.empty()) {
runtime.TransitionImageLayout(image);
return;
@@ -1445,6 +1451,21 @@ void TextureCache<P>::RefreshSparseLayers(Image& image) {
}
template <class P>
+std::vector<u32> TextureCache<P>::BindSparseLayers(Image& image, std::span<const u32> layers) {
+ if constexpr (requires { &Image::BindLayers; }) {
+ const u64 bound_bytes = ImageMemoryBytes(image);
+ std::vector<u32> bound = image.BindLayers(layers);
+ // RegisterImage counts what an image has bound by then; later binds are added here.
+ if (True(image.flags & ImageFlagBits::Registered)) {
+ total_used_memory += ImageMemoryBytes(image) - bound_bytes;
+ }
+ return bound;
+ } else {
+ return {};
+ }
+}
+
+template <class P>
void TextureCache<P>::UploadLayers(Image& image, std::span<const u32> layers) {
if constexpr (requires { &Runtime::AccelerateImageUploadLayers; }) {
if (False(image.flags & ImageFlagBits::AcceleratedUpload)) {
@@ -1714,6 +1735,26 @@ u64 TextureCache<P>::GetScaledImageSizeBytes(const ImageBase& image) {
}
template <class P>
+u64 TextureCache<P>::ImageMemoryBytes(const Image& image) const {
+ if (True(image.flags & ImageFlagBits::Unbacked)) {
+ // No device memory but what BindLayers gave a SparseLayers image: at its full size (GBs
+ // for title 1's sparse terrain images), deleting it would look to the collector like
+ // freeing that much.
+ if constexpr (requires { image.SparseBoundBytes(); }) {
+ return image.SparseBoundBytes();
+ }
+ return 0;
+ }
+ u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
+ if ((IsPixelFormatASTC(image.info.format) &&
+ True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
+ True(image.flags & ImageFlagBits::Converted)) {
+ tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
+ }
+ return Common::AlignUp(tentative_size, 1024);
+}
+
+template <class P>
void TextureCache<P>::QueueAsyncDecode(Image& image, ImageId image_id) {
UNIMPLEMENTED_IF(False(image.flags & ImageFlagBits::Converted));
LOG_DEBUG(HW_GPU, "Queuing async texture decode {:#x}", image.gpu_addr);
@@ -2613,13 +2654,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered),
"Trying to register an already registered image");
image.flags |= ImageFlagBits::Registered;
- u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
- if ((IsPixelFormatASTC(image.info.format) &&
- True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
- True(image.flags & ImageFlagBits::Converted)) {
- tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
- }
- total_used_memory += Common::AlignUp(tentative_size, 1024);
+ total_used_memory += ImageMemoryBytes(slot_images[image_id]);
image.lru_index = lru_cache.Insert(image_id, frame_tick);
ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, image_id](u64 page) {
@@ -2795,13 +2830,8 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
if (image.HasScaled()) {
total_used_memory -= GetScaledImageSizeBytes(image);
}
- u64 tentative_size = (std::max)(image.guest_size_bytes, image.unswizzled_size_bytes);
- if ((IsPixelFormatASTC(image.info.format) &&
- True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
- True(image.flags & ImageFlagBits::Converted)) {
- tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
- }
- total_used_memory -= Common::AlignUp(tentative_size, 1024);
+ // TickFrame sets the total from the driver, which can be under the sum of these estimates.
+ total_used_memory -= (std::min)(total_used_memory, ImageMemoryBytes(slot_images[image_id]));
const GPUVAddr gpu_addr = image.gpu_addr;
const auto alloc_it = image_allocs_table.find(gpu_addr);
if (alloc_it == image_allocs_table.end()) {
@@ -3000,7 +3030,7 @@ void TextureCache<P>::PrepareImage(ImageId image_id, bool is_modification, bool
std::vector<u32> layers(static_cast<size_t>(image.info.resources.layers));
std::iota(layers.begin(), layers.end(), 0U);
// Layers over the image's memory cap stay unbacked (logged once).
- image.BindLayers(layers);
+ BindSparseLayers(image, layers);
}
}
if (True(image.flags & ImageFlagBits::UnwrittenSparse) &&