diff options
| author | DrChat <arkolbed@gmail.com> | 2018-02-10 21:08:17 -0600 |
|---|---|---|
| committer | DrChat <arkolbed@gmail.com> | 2018-02-10 21:08:17 -0600 |
| commit | d015de4a84dce2a7bfea9b765ca6afe036579777 (patch) | |
| tree | 303264d6934dd5d7a2c31263e0aabcac74fa5d8d | |
| parent | e3787c05c14486cfcb6187d3a9cb11185ee98078 (diff) | |
[Vulkan] Smarter transient cache
Detect cases where requested vertex data has already been uploaded in a larger buffer
| -rw-r--r-- | src/xenia/gpu/vulkan/buffer_cache.cc | 33 | ||||
| -rw-r--r-- | 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<ui::vulkan::CircularBuffer> transient_buffer_ = nullptr; - std::map<uint64_t, VkDeviceSize> transient_cache_; + std::map<uint32_t, std::pair<uint32_t, VkDeviceSize>> transient_cache_; VkDescriptorPool descriptor_pool_ = nullptr; VkDescriptorSetLayout descriptor_set_layout_ = nullptr; |
