Files
test/source/blender/gpu/vulkan/vk_descriptor_set.cc
Jeroen Bakker 1497e37728 Cleanup: Vulkan: Descriptor set allocations
During descriptor set update several internal buffers where reallocated
over and over. As descriptor set updates are done very often (1000s
times per frame) some performance could be gained by keeping the
previous allocated buffers around.

Pull Request: https://projects.blender.org/blender/blender/pulls/124877
2024-07-17 14:38:44 +02:00

239 lines
8.4 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup gpu
*/
#include "vk_descriptor_set.hh"
#include "vk_index_buffer.hh"
#include "vk_sampler.hh"
#include "vk_shader.hh"
#include "vk_storage_buffer.hh"
#include "vk_texture.hh"
#include "vk_uniform_buffer.hh"
#include "vk_vertex_buffer.hh"
#include "BLI_assert.h"
namespace blender::gpu {
VKDescriptorSet::VKDescriptorSet(VKDescriptorSet &&other)
: vk_descriptor_pool_(other.vk_descriptor_pool_), vk_descriptor_set_(other.vk_descriptor_set_)
{
other.vk_descriptor_set_ = VK_NULL_HANDLE;
other.vk_descriptor_pool_ = VK_NULL_HANDLE;
}
VKDescriptorSet::~VKDescriptorSet()
{
if (vk_descriptor_set_ != VK_NULL_HANDLE) {
/* Handle should be given back to the pool. */
const VKDevice &device = VKBackend::get().device;
vkFreeDescriptorSets(device.vk_handle(), vk_descriptor_pool_, 1, &vk_descriptor_set_);
vk_descriptor_set_ = VK_NULL_HANDLE;
vk_descriptor_pool_ = VK_NULL_HANDLE;
}
}
void VKDescriptorSetTracker::bind(VKStorageBuffer &buffer,
const VKDescriptorSet::Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
binding.vk_buffer = buffer.vk_handle();
binding.buffer_size = buffer.size_in_bytes();
}
void VKDescriptorSetTracker::bind_as_ssbo(VKVertexBuffer &buffer,
const VKDescriptorSet::Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
binding.vk_buffer = buffer.vk_handle();
binding.buffer_size = buffer.size_used_get();
}
void VKDescriptorSetTracker::bind(VKUniformBuffer &buffer,
const VKDescriptorSet::Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
binding.vk_buffer = buffer.vk_handle();
binding.buffer_size = buffer.size_in_bytes();
}
void VKDescriptorSetTracker::bind_as_ssbo(VKIndexBuffer &buffer,
const VKDescriptorSet::Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
binding.vk_buffer = buffer.vk_handle();
binding.buffer_size = buffer.size_get();
}
void VKDescriptorSetTracker::bind_as_ssbo(VKUniformBuffer &buffer,
const VKDescriptorSet::Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
binding.vk_buffer = buffer.vk_handle();
binding.buffer_size = buffer.size_in_bytes();
}
void VKDescriptorSetTracker::image_bind(VKTexture &texture,
const VKDescriptorSet::Location location,
VKImageViewArrayed arrayed)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
binding.texture = &texture;
binding.arrayed = arrayed;
}
void VKDescriptorSetTracker::bind(VKTexture &texture,
const VKDescriptorSet::Location location,
const VKSampler &sampler,
VKImageViewArrayed arrayed)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding.texture = &texture;
binding.vk_sampler = sampler.vk_handle();
binding.arrayed = arrayed;
}
void VKDescriptorSetTracker::bind(VKVertexBuffer &vertex_buffer,
const VKDescriptorSet::Location location)
{
Binding &binding = ensure_location(location);
binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
binding.vk_buffer_view = vertex_buffer.vk_buffer_view_get();
binding.buffer_size = vertex_buffer.size_alloc_get();
}
VKDescriptorSetTracker::Binding &VKDescriptorSetTracker::ensure_location(
const VKDescriptorSet::Location location)
{
for (Binding &binding : bindings_) {
if (binding.location == location) {
return binding;
}
}
Binding binding = {};
binding.location = location;
bindings_.append(binding);
return bindings_.last();
}
void VKDescriptorSetTracker::update(VKContext &context)
{
const VKShader &shader = *unwrap(context.shader);
VkDescriptorSetLayout vk_descriptor_set_layout = shader.vk_descriptor_set_layout_get();
active_vk_descriptor_set_layout = vk_descriptor_set_layout;
tracked_resource_for(context, true);
std::unique_ptr<VKDescriptorSet> &descriptor_set = active_descriptor_set();
VkDescriptorSet vk_descriptor_set = descriptor_set->vk_handle();
BLI_assert(vk_descriptor_set != VK_NULL_HANDLE);
debug::object_label(vk_descriptor_set, shader.name_get());
/* Ensure that the local arrays contain enough space to store the bindings. */
BLI_assert_msg(vk_descriptor_image_infos_.is_empty() && vk_descriptor_buffer_infos_.is_empty() &&
vk_write_descriptor_sets_.is_empty(),
"Incorrect usage, internal vectors should be empty.");
if (vk_descriptor_buffer_infos_.capacity() < bindings_.size()) {
vk_descriptor_buffer_infos_.reserve(bindings_.size() * 2);
vk_descriptor_image_infos_.reserve(bindings_.size() * 2);
}
for (const Binding &binding : bindings_) {
if (!binding.is_buffer()) {
continue;
}
vk_descriptor_buffer_infos_.append({binding.vk_buffer, 0, binding.buffer_size});
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
binding.location,
0,
1,
binding.type,
nullptr,
&vk_descriptor_buffer_infos_.last(),
nullptr});
}
for (const Binding &binding : bindings_) {
if (!binding.is_texel_buffer()) {
continue;
}
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
binding.location,
0,
1,
binding.type,
nullptr,
nullptr,
&binding.vk_buffer_view});
}
for (const Binding &binding : bindings_) {
if (!binding.is_image()) {
continue;
}
/* TODO: Based on the actual usage we should use
* VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL. */
vk_descriptor_image_infos_.append(
{binding.vk_sampler,
binding.texture->image_view_get(binding.arrayed).vk_handle(),
VK_IMAGE_LAYOUT_GENERAL});
vk_write_descriptor_sets_.append({VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
nullptr,
vk_descriptor_set,
binding.location,
0,
1,
binding.type,
&vk_descriptor_image_infos_.last(),
nullptr,
nullptr});
}
const VKDevice &device = VKBackend::get().device;
vkUpdateDescriptorSets(device.vk_handle(),
vk_write_descriptor_sets_.size(),
vk_write_descriptor_sets_.data(),
0,
nullptr);
bindings_.clear();
vk_descriptor_image_infos_.clear();
vk_descriptor_buffer_infos_.clear();
vk_write_descriptor_sets_.clear();
}
std::unique_ptr<VKDescriptorSet> VKDescriptorSetTracker::create_resource(VKContext &context)
{
return context.descriptor_pools_get().allocate(active_vk_descriptor_set_layout);
}
void VKDescriptorSetTracker::debug_print() const
{
for (const Binding &binding : bindings_) {
binding.debug_print();
}
}
void VKDescriptorSetTracker::Binding::debug_print() const
{
std::cout << "VkDescriptorSetTrackker::Binding(type: " << type
<< ", location:" << location.binding << ")\n";
}
} // namespace blender::gpu