From d015de4a84dce2a7bfea9b765ca6afe036579777 Mon Sep 17 00:00:00 2001 From: DrChat Date: Sat, 10 Feb 2018 21:08:17 -0600 Subject: [PATCH] [Vulkan] Smarter transient cache Detect cases where requested vertex data has already been uploaded in a larger buffer --- src/xenia/gpu/vulkan/buffer_cache.cc | 33 +++++++++++++++++++++++----- src/xenia/gpu/vulkan/buffer_cache.h | 2 +- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/xenia/gpu/vulkan/buffer_cache.cc b/src/xenia/gpu/vulkan/buffer_cache.cc index 287292021..1b4253bdd 100644 --- a/src/xenia/gpu/vulkan/buffer_cache.cc +++ b/src/xenia/gpu/vulkan/buffer_cache.cc @@ -415,10 +415,22 @@ VkDeviceSize BufferCache::TryAllocateTransientData(VkDeviceSize length, VkDeviceSize BufferCache::FindCachedTransientData(uint32_t guest_address, uint32_t guest_length) { - uint64_t key = uint64_t(guest_length) << 32 | uint64_t(guest_address); - auto it = transient_cache_.find(key); - if (it != transient_cache_.end()) { - return it->second; + if (transient_cache_.empty()) { + // Short-circuit exit. + return VK_WHOLE_SIZE; + } + + // Find the first element > guest_address + auto it = transient_cache_.upper_bound(guest_address); + if (it != transient_cache_.begin()) { + // it = first element < guest_address + --it; + + if (it->first <= guest_address && + (it->first + it->second.first) >= (guest_address + guest_length)) { + // This element is contained within some existing transient data. + return it->second.second + (guest_address - it->first); + } } return VK_WHOLE_SIZE; @@ -427,8 +439,17 @@ VkDeviceSize BufferCache::FindCachedTransientData(uint32_t guest_address, void BufferCache::CacheTransientData(uint32_t guest_address, uint32_t guest_length, VkDeviceSize offset) { - uint64_t key = uint64_t(guest_length) << 32 | uint64_t(guest_address); - transient_cache_[key] = offset; + transient_cache_[guest_address] = {guest_length, offset}; + + // Erase any entries contained within + auto it = transient_cache_.upper_bound(guest_address); + while (it != transient_cache_.end()) { + if ((guest_address + guest_length) >= (it->first + it->second.first)) { + it = transient_cache_.erase(it); + } else { + break; + } + } } void BufferCache::Flush(VkCommandBuffer command_buffer) { diff --git a/src/xenia/gpu/vulkan/buffer_cache.h b/src/xenia/gpu/vulkan/buffer_cache.h index 304455404..513aa4f65 100644 --- a/src/xenia/gpu/vulkan/buffer_cache.h +++ b/src/xenia/gpu/vulkan/buffer_cache.h @@ -122,7 +122,7 @@ class BufferCache { // Staging ringbuffer we cycle through fast. Used for data we don't // plan on keeping past the current frame. std::unique_ptr transient_buffer_ = nullptr; - std::map transient_cache_; + std::map> transient_cache_; VkDescriptorPool descriptor_pool_ = nullptr; VkDescriptorSetLayout descriptor_set_layout_ = nullptr;