[Vulkan] Hash and track vertex descriptor sets (similar to texture cache)
This commit is contained in:
parent
2a908eb86d
commit
1a263f14a2
|
@ -543,9 +543,46 @@ std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadVertexBuffer(
|
||||||
return {transient_buffer_->gpu_buffer(), offset + source_offset};
|
return {transient_buffer_->gpu_buffer(), offset + source_offset};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BufferCache::HashVertexBindings(
|
||||||
|
XXH64_state_t* hash_state,
|
||||||
|
const std::vector<Shader::VertexBinding>& vertex_bindings) {
|
||||||
|
auto& regs = *register_file_;
|
||||||
|
for (const auto& vertex_binding : vertex_bindings) {
|
||||||
|
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 +
|
||||||
|
(vertex_binding.fetch_constant / 3) * 6;
|
||||||
|
const auto group = reinterpret_cast<xe_gpu_fetch_group_t*>(®s.values[r]);
|
||||||
|
const xe_gpu_vertex_fetch_t* fetch = nullptr;
|
||||||
|
switch (vertex_binding.fetch_constant % 3) {
|
||||||
|
case 0:
|
||||||
|
fetch = &group->vertex_fetch_0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fetch = &group->vertex_fetch_1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fetch = &group->vertex_fetch_2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
XXH64_update(hash_state, fetch, sizeof(fetch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VkDescriptorSet BufferCache::PrepareVertexSet(
|
VkDescriptorSet BufferCache::PrepareVertexSet(
|
||||||
VkCommandBuffer command_buffer, VkFence fence,
|
VkCommandBuffer command_buffer, VkFence fence,
|
||||||
std::vector<Shader::VertexBinding> vertex_bindings) {
|
const std::vector<Shader::VertexBinding>& vertex_bindings) {
|
||||||
|
// (quickly) Generate a hash.
|
||||||
|
XXH64_state_t hash_state;
|
||||||
|
XXH64_reset(&hash_state, 0);
|
||||||
|
|
||||||
|
// (quickly) Generate a hash.
|
||||||
|
HashVertexBindings(&hash_state, vertex_bindings);
|
||||||
|
uint64_t hash = XXH64_digest(&hash_state);
|
||||||
|
for (auto it = vertex_sets_.find(hash); it != vertex_sets_.end(); ++it) {
|
||||||
|
// TODO(DrChat): We need to compare the bindings and ensure they're equal.
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
if (!vertex_descriptor_pool_->has_open_batch()) {
|
if (!vertex_descriptor_pool_->has_open_batch()) {
|
||||||
vertex_descriptor_pool_->BeginBatch(fence);
|
vertex_descriptor_pool_->BeginBatch(fence);
|
||||||
}
|
}
|
||||||
|
@ -621,6 +658,7 @@ VkDescriptorSet BufferCache::PrepareVertexSet(
|
||||||
}
|
}
|
||||||
|
|
||||||
vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
|
vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
|
||||||
|
vertex_sets_[hash] = set;
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -718,6 +756,10 @@ void BufferCache::ClearCache() { transient_cache_.clear(); }
|
||||||
void BufferCache::Scavenge() {
|
void BufferCache::Scavenge() {
|
||||||
transient_cache_.clear();
|
transient_cache_.clear();
|
||||||
transient_buffer_->Scavenge();
|
transient_buffer_->Scavenge();
|
||||||
|
|
||||||
|
// TODO(DrChat): These could persist across frames, we just need a smart way
|
||||||
|
// to delete unused ones.
|
||||||
|
vertex_sets_.clear();
|
||||||
if (vertex_descriptor_pool_->has_open_batch()) {
|
if (vertex_descriptor_pool_->has_open_batch()) {
|
||||||
vertex_descriptor_pool_->EndBatch();
|
vertex_descriptor_pool_->EndBatch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,10 @@
|
||||||
#include "xenia/ui/vulkan/vulkan_device.h"
|
#include "xenia/ui/vulkan/vulkan_device.h"
|
||||||
|
|
||||||
#include "third_party/vulkan/vk_mem_alloc.h"
|
#include "third_party/vulkan/vk_mem_alloc.h"
|
||||||
|
#include "third_party/xxhash/xxhash.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
@ -89,7 +91,7 @@ class BufferCache {
|
||||||
// Prepares and returns a vertex descriptor set.
|
// Prepares and returns a vertex descriptor set.
|
||||||
VkDescriptorSet PrepareVertexSet(
|
VkDescriptorSet PrepareVertexSet(
|
||||||
VkCommandBuffer setup_buffer, VkFence fence,
|
VkCommandBuffer setup_buffer, VkFence fence,
|
||||||
std::vector<Shader::VertexBinding> vertex_bindings);
|
const std::vector<Shader::VertexBinding>& vertex_bindings);
|
||||||
|
|
||||||
// Flushes all pending data to the GPU.
|
// Flushes all pending data to the GPU.
|
||||||
// Until this is called the GPU is not guaranteed to see any data.
|
// Until this is called the GPU is not guaranteed to see any data.
|
||||||
|
@ -124,6 +126,10 @@ class BufferCache {
|
||||||
VkResult CreateConstantDescriptorSet();
|
VkResult CreateConstantDescriptorSet();
|
||||||
void FreeConstantDescriptorSet();
|
void FreeConstantDescriptorSet();
|
||||||
|
|
||||||
|
void HashVertexBindings(
|
||||||
|
XXH64_state_t* hash_state,
|
||||||
|
const std::vector<Shader::VertexBinding>& vertex_bindings);
|
||||||
|
|
||||||
// Allocates a block of memory in the transient buffer.
|
// Allocates a block of memory in the transient buffer.
|
||||||
// When memory is not available fences are checked and space is reclaimed.
|
// When memory is not available fences are checked and space is reclaimed.
|
||||||
// Returns VK_WHOLE_SIZE if requested amount of memory is not available.
|
// Returns VK_WHOLE_SIZE if requested amount of memory is not available.
|
||||||
|
@ -155,6 +161,9 @@ class BufferCache {
|
||||||
std::unique_ptr<ui::vulkan::DescriptorPool> vertex_descriptor_pool_ = nullptr;
|
std::unique_ptr<ui::vulkan::DescriptorPool> vertex_descriptor_pool_ = nullptr;
|
||||||
VkDescriptorSetLayout vertex_descriptor_set_layout_ = nullptr;
|
VkDescriptorSetLayout vertex_descriptor_set_layout_ = nullptr;
|
||||||
|
|
||||||
|
// Current frame vertex sets.
|
||||||
|
std::unordered_map<uint64_t, VkDescriptorSet> vertex_sets_;
|
||||||
|
|
||||||
// Descriptor set used to hold vertex/pixel shader float constants
|
// Descriptor set used to hold vertex/pixel shader float constants
|
||||||
VkDescriptorPool constant_descriptor_pool_ = nullptr;
|
VkDescriptorPool constant_descriptor_pool_ = nullptr;
|
||||||
VkDescriptorSetLayout constant_descriptor_set_layout_ = nullptr;
|
VkDescriptorSetLayout constant_descriptor_set_layout_ = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue