diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index fff57ffa9c..d2be26bb5a 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -23,42 +23,94 @@ BufferCache
::BufferCache(VideoCore::RasterizerInterface& rasterizer_,
common_ranges.clear();
inline_buffer_id = NULL_BUFFER_ID;
- if (!runtime.CanReportMemoryUsage()) {
- minimum_memory = DEFAULT_EXPECTED_MEMORY;
- critical_memory = DEFAULT_CRITICAL_MEMORY;
- return;
- }
-
const s64 device_memory = static_cast ::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 auto clean_up = [this, &num_iterations](BufferId buffer_id) {
+ if (total_used_memory < minimum_memory) {
+ return;
+ }
+ bool is_expected = total_used_memory >= expected_memory;
+ bool is_critical = total_used_memory >= critical_memory;
+ const u64 ticks_to_destroy = is_critical ? 60ULL : is_expected ? 120ULL : 240ULL;
+ size_t num_iterations = is_critical ? 40 : (is_expected ? 20 : 10);
+ boost::container::small_vector ::TickFrame() {
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()) {
+ if (runtime.CanReportMemoryUsage() && frame_tick % 60 == 0) {
total_used_memory = runtime.GetDeviceMemoryUsage();
}
- if (total_used_memory >= minimum_memory) {
- RunGarbageCollector();
- }
+ RunGarbageCollector();
++frame_tick;
delayed_destruction_ring.Tick();
@@ -1556,17 +1606,13 @@ bool BufferCache ::InlineMemory(VAddr dest_address, size_t copy_size,
}
template ::DownloadBufferMemory(Buffer& buffer) {
- DownloadBufferMemory(buffer, buffer.CpuAddr(), buffer.SizeBytes());
-}
-
-template ::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 size) {
- boost::container::small_vector ::FullDownloadCopies(Buffer& buffer, VAddr cpu_addr,
+ u64 size, bool clear) {
+ boost::container::small_vector ::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
ClearDownload(subtract_interval);
common_ranges.subtract(subtract_interval);
});
- if (total_size_bytes == 0) {
+ return {total_size_bytes, largest_copy, std::move(copies)};
+}
+
+template ::DownloadBufferMemory(Buffer& buffer) {
+ DownloadBufferMemory(buffer, buffer.CpuAddr(), buffer.SizeBytes());
+}
+
+template ::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 size) {
+ auto buffer_copies = FullDownloadCopies(buffer, cpu_addr, size);
+ if (buffer_copies.total_size == 0) {
return;
}
+
MICROPROFILE_SCOPE(GPU_DownloadMemory);
if constexpr (USE_MEMORY_MAPS) {
- auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
+ auto download_staging = runtime.DownloadStagingBuffer(buffer_copies.total_size);
const u8* const mapped_memory = download_staging.mapped_span.data();
- const std::span ::DownloadBufferMemory(Buffer& buffer, VAddr cpu_addr, u64 si
cpu_memory.WriteBlockUnsafe(copy_cpu_addr, copy_mapped_memory, copy.size);
}
} else {
- const std::span ::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
void(slot_image_views.insert(runtime, NullImageViewParams{}));
void(slot_samplers.insert(runtime, sampler_descriptor));
- if constexpr (HAS_DEVICE_MEMORY_INFO) {
- const s64 device_memory = static_cast ::RunGarbageCollector() {
- bool high_priority_mode = total_used_memory >= expected_memory;
- bool aggressive_mode = total_used_memory >= critical_memory;
- const u64 ticks_to_destroy = aggressive_mode ? 10ULL : high_priority_mode ? 25ULL : 50ULL;
- size_t num_iterations = aggressive_mode ? 40 : (high_priority_mode ? 20 : 10);
- const auto clean_up = [this, &num_iterations, &high_priority_mode,
- &aggressive_mode](ImageId image_id) {
+ if (total_used_memory < minimum_memory) {
+ return;
+ }
+ bool is_expected = total_used_memory >= expected_memory;
+ bool is_critical = total_used_memory >= critical_memory;
+ const u64 ticks_to_destroy = is_critical ? 10ULL : is_expected ? 25ULL : 50ULL;
+ size_t num_iterations = is_critical ? 40 : (is_expected ? 20 : 10);
+ boost::container::small_vector<
+ std::tuple ::RunGarbageCollector() {
// used by the async decoder thread.
return false;
}
- const bool must_download =
- image.IsSafeDownload() && False(image.flags & ImageFlagBits::BadOverlap);
- if (!high_priority_mode &&
- (must_download || True(image.flags & ImageFlagBits::CostlyLoad))) {
- return false;
- }
- if (must_download) {
- auto map = runtime.DownloadStagingBuffer(image.unswizzled_size_bytes);
- const auto copies = FullDownloadCopies(image.info);
- image.DownloadMemory(map, copies);
- runtime.Finish();
- SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span,
- swizzle_data_buffer);
- }
- if (True(image.flags & ImageFlagBits::Tracked)) {
- UntrackImage(image, image_id);
- }
- UnregisterImage(image_id);
- DeleteImage(image_id, image.scale_tick > frame_tick + 5);
- if (total_used_memory < critical_memory) {
- if (aggressive_mode) {
- // Sink the aggresiveness.
- num_iterations >>= 2;
- aggressive_mode = false;
- return false;
- }
- if (high_priority_mode && total_used_memory < expected_memory) {
- num_iterations >>= 1;
- high_priority_mode = false;
- }
+
+ const bool do_download = image.IsSafeDownload() &&
+ False(image.flags & ImageFlagBits::BadOverlap) &&
+ (False(image.flags & ImageFlagBits::CostlyLoad) || is_critical);
+ if (do_download) {
+ total_download_size += image.unswizzled_size_bytes;
+ largest_download_size = std::max(largest_download_size, image.unswizzled_size_bytes);
}
+ to_delete.push_back({image_id, do_download, {}});
return false;
};
lru_cache.ForEachItemBelow(frame_tick - ticks_to_destroy, clean_up);
+
+ if (total_download_size > 0) {
+ auto map = runtime.DownloadStagingBuffer(total_download_size);
+ for (auto& [image_id, do_download, copies] : to_delete) {
+ if (!do_download) {
+ continue;
+ }
+ Image& image = slot_images[image_id];
+ copies = FullDownloadCopies(image.info);
+ image.DownloadMemory(map, copies);
+ map.offset += Common::AlignUp(image.unswizzled_size_bytes, 64);
+ }
+
+ runtime.Finish();
+ swizzle_data_buffer.resize_destructive(Common::AlignUp(largest_download_size, 1024));
+
+ u64 offset{0};
+ for (auto& [image_id, do_download, copies] : to_delete) {
+ Image& image = slot_images[image_id];
+ if (do_download) {
+ for (auto& copy : copies) {
+ copy.buffer_offset += offset;
+ }
+ SwizzleImage(*gpu_memory, image.gpu_addr, image.info, copies, map.mapped_span,
+ swizzle_data_buffer);
+ offset += Common::AlignUp(image.unswizzled_size_bytes, 64);
+ }
+ if (True(image.flags & ImageFlagBits::Tracked)) {
+ UntrackImage(image, image_id);
+ }
+ UnregisterImage(image_id);
+ DeleteImage(image_id, image.scale_tick > frame_tick + 5);
+ }
+ } else {
+ for (auto& [image_id, do_download, copies] : to_delete) {
+ Image& image = slot_images[image_id];
+ if (True(image.flags & ImageFlagBits::Tracked)) {
+ UntrackImage(image, image_id);
+ }
+ UnregisterImage(image_id);
+ DeleteImage(image_id, image.scale_tick > frame_tick + 5);
+ }
+ }
}
template ::TickFrame() {
// If we can obtain the memory info, use it instead of the estimate.
- if (runtime.CanReportMemoryUsage()) {
+ if (runtime.CanReportMemoryUsage() && frame_tick % 60 == 0) {
total_used_memory = runtime.GetDeviceMemoryUsage();
}
- if (total_used_memory > minimum_memory) {
- RunGarbageCollector();
- }
+ RunGarbageCollector();
sentenced_images.Tick();
sentenced_framebuffers.Tick();
sentenced_image_view.Tick();
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h
index a0e10643f3..aa7769ea02 100644
--- a/src/video_core/texture_cache/types.h
+++ b/src/video_core/texture_cache/types.h
@@ -3,6 +3,8 @@
#pragma once
+#include