Resource binding was over-complicated as I didn't understood the state manager and vulkan to make the correct decisions at that time. This refactor will remove a lot of the complexity and improves the performance. **Performance** The performance improvement is noticeable in complex grease pencil scenes. Grease pencil benchmark file picknick: - `NVIDIA Quadro RTX 6000` 17 fps -> 24 fps - `Intel(R) Arc(tm) A750 Graphics (DG2)` 6 -> 21 fps **Bottle-neck** The performance improvements originates from moving the update entry point from state manager to shader interface. The previous implementation (state manager) had to loop over all the bound resources and find in the shader interface where it was located in the descriptor set. Ignoring resources that were not used by the shader. But also making it hard to determine if descriptor sets actually changed. Previous implementation assumed descriptor sets always changed. When descriptor set changed a new descriptor set needed to be allocated. Most drivers this is a fast operation, but on Intel/Mesa this was measurable slow. Using an allocation pool doesn't fit the Vulkan API as you are only able to reuse when the layout matches exactly. Of course doable, but requires another structure to keep track of the actual layouts. **Solution** By using the shader interface as entry point we can: 1. Keep track if there are any changes in the state manager. If not and the layout is the same, the previous shader can be reused. 2. In stead of looping over each bound resource, we loop over bind points. **Future extensions** Bundle all descriptor set uploads just before use. This would be more in line with how 'modern' Vulkan should be implemented. This PR already separates the uploading from the updating and technically allows to upload more than one descriptor set. Instead of looking 1 set back we should measure if we can handle multiple or keep track of the different layouts resources to improve the performance even further. Optional use `VK_KHR_descriptor_buffer` when available. Pull Request: https://projects.blender.org/blender/blender/pulls/128068
117 lines
3.7 KiB
C++
117 lines
3.7 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "BLI_array.hh"
|
|
|
|
#include "gpu_shader_create_info.hh"
|
|
#include "gpu_shader_interface.hh"
|
|
|
|
#include "BLI_array.hh"
|
|
|
|
#include "vk_descriptor_set_layouts.hh"
|
|
#include "vk_push_constants.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
struct VKResourceBinding {
|
|
shader::ShaderCreateInfo::Resource::BindType bind_type =
|
|
shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER;
|
|
int binding = -1;
|
|
|
|
VKDescriptorSet::Location location;
|
|
VKImageViewArrayed arrayed = VKImageViewArrayed::DONT_CARE;
|
|
VkAccessFlags access_mask = VK_ACCESS_NONE;
|
|
};
|
|
|
|
class VKShaderInterface : public ShaderInterface {
|
|
private:
|
|
/** Binding information for each shader input. */
|
|
Array<VKResourceBinding> resource_bindings_;
|
|
VKDescriptorSetLayoutInfo descriptor_set_layout_info_;
|
|
|
|
VKPushConstants::Layout push_constants_layout_;
|
|
|
|
shader::BuiltinBits shader_builtins_;
|
|
|
|
public:
|
|
VKShaderInterface() = default;
|
|
|
|
void init(const shader::ShaderCreateInfo &info);
|
|
|
|
const VKDescriptorSet::Location descriptor_set_location(
|
|
const shader::ShaderCreateInfo::Resource &resource) const;
|
|
const std::optional<VKDescriptorSet::Location> descriptor_set_location(
|
|
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
|
|
|
|
/**
|
|
* Get the access mask for a binding.
|
|
*
|
|
* Is used to build the correct resource accesses in the render graph (dispatch/draw nodes).
|
|
*
|
|
* Will return VK_ACCESS_NONE when binding isn't found or not compatible with the given bind
|
|
* type.
|
|
*/
|
|
const VkAccessFlags access_mask(const shader::ShaderCreateInfo::Resource::BindType &bind_type,
|
|
int binding) const;
|
|
const VKImageViewArrayed arrayed(const shader::ShaderCreateInfo::Resource::BindType &bind_type,
|
|
int binding) const;
|
|
|
|
/** Get the Layout of the shader. */
|
|
const VKPushConstants::Layout &push_constants_layout_get() const
|
|
{
|
|
return push_constants_layout_;
|
|
}
|
|
|
|
const VKDescriptorSetLayoutInfo &descriptor_set_layout_info_get() const
|
|
{
|
|
return descriptor_set_layout_info_;
|
|
}
|
|
|
|
shader::Type get_attribute_type(int location) const
|
|
{
|
|
return static_cast<shader::Type>(attr_types_[location]);
|
|
}
|
|
|
|
bool is_point_shader() const
|
|
{
|
|
return (shader_builtins_ & shader::BuiltinBits::POINT_SIZE) == shader::BuiltinBits::POINT_SIZE;
|
|
}
|
|
|
|
const Span<VKResourceBinding> resource_bindings_get() const
|
|
{
|
|
return resource_bindings_;
|
|
}
|
|
|
|
private:
|
|
void init_descriptor_set_layout_info(const shader::ShaderCreateInfo &info,
|
|
int64_t resources_len,
|
|
Span<shader::ShaderCreateInfo::Resource> resources,
|
|
VKPushConstants::StorageType push_constants_storage);
|
|
/**
|
|
* Retrieve the shader input for the given resource.
|
|
*
|
|
* nullptr is returned when resource could not be found.
|
|
* Should only happen when still developing the Vulkan shader.
|
|
*/
|
|
const ShaderInput *shader_input_get(const shader::ShaderCreateInfo::Resource &resource) const;
|
|
const ShaderInput *shader_input_get(
|
|
const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const;
|
|
const VKResourceBinding &resource_binding_info(const ShaderInput *shader_input) const;
|
|
|
|
void descriptor_set_location_update(
|
|
const ShaderInput *shader_input,
|
|
const VKDescriptorSet::Location location,
|
|
const shader::ShaderCreateInfo::Resource::BindType bind_type,
|
|
std::optional<const shader::ShaderCreateInfo::Resource> resource,
|
|
VKImageViewArrayed arrayed);
|
|
};
|
|
|
|
} // namespace blender::gpu
|