summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrChat <arkolbed@gmail.com>2018-02-10 21:08:17 -0600
committerDrChat <arkolbed@gmail.com>2018-02-10 21:08:17 -0600
commitd015de4a84dce2a7bfea9b765ca6afe036579777 (patch)
tree303264d6934dd5d7a2c31263e0aabcac74fa5d8d
parente3787c05c14486cfcb6187d3a9cb11185ee98078 (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.cc33
-rw-r--r--src/xenia/gpu/vulkan/buffer_cache.h2
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;