Vulkan: Add basic one-frame cache to BufferCache

This commit is contained in:
Dr. Chat
2017-01-29 00:24:31 -06:00
parent d9b52d1afa
commit 8c79051a94
5 changed files with 81 additions and 28 deletions

View File

@@ -25,9 +25,9 @@ using xe::ui::vulkan::CheckResult;
constexpr VkDeviceSize kConstantRegisterUniformRange =
512 * 4 * 4 + 8 * 4 + 32 * 4;
BufferCache::BufferCache(RegisterFile* register_file,
BufferCache::BufferCache(RegisterFile* register_file, Memory* memory,
ui::vulkan::VulkanDevice* device, size_t capacity)
: register_file_(register_file), device_(*device) {
: register_file_(register_file), memory_(memory), device_(*device) {
transient_buffer_ = std::make_unique<ui::vulkan::CircularBuffer>(
device,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
@@ -229,15 +229,22 @@ std::pair<VkDeviceSize, VkDeviceSize> BufferCache::UploadConstantRegisters(
}
std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadIndexBuffer(
const void* source_ptr, size_t source_length, IndexFormat format,
uint32_t source_addr, uint32_t source_length, IndexFormat format,
VkFence fence) {
auto offset = FindCachedTransientData(source_addr, source_length);
if (offset != VK_WHOLE_SIZE) {
return {transient_buffer_->gpu_buffer(), offset};
}
// Allocate space in the buffer for our data.
auto offset = AllocateTransientData(source_length, fence);
offset = AllocateTransientData(source_length, fence);
if (offset == VK_WHOLE_SIZE) {
// OOM.
return {nullptr, VK_WHOLE_SIZE};
}
const void* source_ptr = memory_->TranslatePhysical(source_addr);
// Copy data into the buffer.
// TODO(benvanik): get min/max indices and pass back?
// TODO(benvanik): memcpy then use compute shaders to swap?
@@ -251,28 +258,41 @@ std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadIndexBuffer(
source_ptr, source_length / 4);
}
CacheTransientData(source_addr, source_length, offset);
return {transient_buffer_->gpu_buffer(), offset};
}
std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadVertexBuffer(
const void* source_ptr, size_t source_length, Endian endian,
uint32_t source_addr, uint32_t source_length, Endian endian,
VkFence fence) {
auto offset = FindCachedTransientData(source_addr, source_length);
if (offset != VK_WHOLE_SIZE) {
return {transient_buffer_->gpu_buffer(), offset};
}
// Allocate space in the buffer for our data.
auto offset = AllocateTransientData(source_length, fence);
offset = AllocateTransientData(source_length, fence);
if (offset == VK_WHOLE_SIZE) {
// OOM.
return {nullptr, VK_WHOLE_SIZE};
}
const void* source_ptr = memory_->TranslatePhysical(source_addr);
// Copy data into the buffer.
// TODO(benvanik): memcpy then use compute shaders to swap?
assert_true(endian == Endian::k8in32);
if (endian == Endian::k8in32) {
// Endian::k8in32, swap words.
xe::copy_and_swap_32_aligned(transient_buffer_->host_base() + offset,
source_ptr, source_length / 4);
} else if (endian == Endian::k16in32) {
xe::copy_and_swap_16_in_32_aligned(transient_buffer_->host_base() + offset,
source_ptr, source_length / 4);
} else {
assert_always();
}
CacheTransientData(source_addr, source_length, offset);
return {transient_buffer_->gpu_buffer(), offset};
}
@@ -304,6 +324,24 @@ VkDeviceSize BufferCache::TryAllocateTransientData(VkDeviceSize length,
return VK_WHOLE_SIZE;
}
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;
}
return VK_WHOLE_SIZE;
}
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;
}
void BufferCache::Flush(VkCommandBuffer command_buffer) {
// If we are flushing a big enough chunk queue up an event.
// We don't want to do this for everything but often enough so that we won't
@@ -331,7 +369,10 @@ void BufferCache::InvalidateCache() {
void BufferCache::ClearCache() { transient_cache_.clear(); }
void BufferCache::Scavenge() { transient_buffer_->Scavenge(); }
void BufferCache::Scavenge() {
transient_cache_.clear();
transient_buffer_->Scavenge();
}
} // namespace vulkan
} // namespace gpu