Vulkan: Fix Namespace Collision Between Shader Resources #112511

Merged
Jeroen Bakker merged 1 commits from Jeroen-Bakker/blender:vulkan/shader-resource-collision into main 2023-09-18 13:41:58 +02:00
4 changed files with 51 additions and 24 deletions

View File

@ -8,8 +8,6 @@
#pragma once
#include "BLI_array.hh"
#include "gpu_shader_create_info.hh"
namespace blender::gpu {
@ -38,22 +36,29 @@ class VKBindableResource {
* Blender binds resources at context level (VKStateManager). The bindings are organized in
* namespaces.
*/
template<shader::ShaderCreateInfo::Resource::BindType BindType, int MaxBindings = 16>
class VKBindSpace {
Array<VKBindableResource *> bindings_ = Array<VKBindableResource *>(MaxBindings);
template<shader::ShaderCreateInfo::Resource::BindType BindType> class VKBindSpace {
class ResourceBinding {
public:
int binding;
VKBindableResource *resource;
};
Vector<ResourceBinding> bindings_;
public:
VKBindSpace()
{
bindings_.fill(nullptr);
}
/**
* Register a binding to this namespace.
*/
void bind(int binding, VKBindableResource &resource)
{
bindings_[binding] = &resource;
for (ResourceBinding &bind : bindings_) {
if (bind.binding == binding) {
bind.resource = &resource;
return;
}
}
ResourceBinding bind = {binding, &resource};
bindings_.append(bind);
}
/**
@ -61,10 +66,8 @@ class VKBindSpace {
*/
void apply_bindings()
{
for (int binding : IndexRange(MaxBindings)) {
if (bindings_[binding] != nullptr) {
bindings_[binding]->bind(binding, BindType);
}
for (ResourceBinding &binding : bindings_) {
binding.resource->bind(binding.binding, BindType);
}
}
@ -73,11 +76,8 @@ class VKBindSpace {
*/
void unbind(VKBindableResource &resource)
{
for (int binding : IndexRange(MaxBindings)) {
if (bindings_[binding] == &resource) {
bindings_[binding] = nullptr;
}
}
bindings_.remove_if(
[&resource](const ResourceBinding &binding) { return binding.resource == &resource; });
}
/**
@ -85,7 +85,7 @@ class VKBindSpace {
*/
void unbind_all()
{
bindings_.fill(nullptr);
bindings_.clear();
}
};

View File

@ -211,4 +211,17 @@ std::unique_ptr<VKDescriptorSet> VKDescriptorSetTracker::create_resource(VKConte
return device.descriptor_pools_get().allocate(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

View File

@ -148,6 +148,8 @@ class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
texture != nullptr;
}
void debug_print() const;
};
private:
@ -191,6 +193,8 @@ class VKDescriptorSetTracker : protected VKResourceTracker<VKDescriptorSet> {
return active_resource();
}
void debug_print() const;
protected:
std::unique_ptr<VKDescriptorSet> create_resource(VKContext &context) override;

View File

@ -24,7 +24,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
ssbo_len_ = 0;
ubo_len_ = 0;
image_offset_ = -1;
int image_max_binding = -1;
Vector<ShaderCreateInfo::Resource> all_resources;
all_resources.extend(info.pass_resources_);
all_resources.extend(info.batch_resources_);
@ -33,6 +33,7 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
switch (res.bind_type) {
case ShaderCreateInfo::Resource::BindType::IMAGE:
uniform_len_++;
image_max_binding = max_ii(image_max_binding, res.slot);
break;
case ShaderCreateInfo::Resource::BindType::SAMPLER:
image_offset_ = max_ii(image_offset_, res.slot);
@ -57,8 +58,11 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
names_size += PUSH_CONSTANTS_FALLBACK_NAME_LEN + 1;
}
/* Make sure that the image slots don't overlap with the sampler slots. */
/* Make sure that the image slots don't overlap with other sampler or image slots. */
image_offset_++;
if (image_offset_ != 0 && image_offset_ <= image_max_binding) {
image_offset_ = image_max_binding + 1;
}
int32_t input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_;
inputs_ = static_cast<ShaderInput *>(
@ -150,9 +154,11 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info)
/* Note: input_tot_len is sometimes more than we need. */
const uint32_t resources_len = input_tot_len;
descriptor_set_locations_ = Array<VKDescriptorSet::Location>(resources_len);
descriptor_set_locations_.fill(-1);
uint32_t descriptor_set_location = 0;
for (ShaderCreateInfo::Resource &res : all_resources) {
const ShaderInput *input = shader_input_get(res);
BLI_assert(input);
descriptor_set_location_update(input, descriptor_set_location++);
}
@ -179,6 +185,7 @@ void VKShaderInterface::descriptor_set_location_update(const ShaderInput *shader
const VKDescriptorSet::Location location)
{
int32_t index = shader_input_index(inputs_, shader_input);
BLI_assert(descriptor_set_locations_[index].binding == -1);
descriptor_set_locations_[index] = location;
}
@ -218,7 +225,10 @@ const ShaderInput *VKShaderInterface::shader_input_get(
{
switch (bind_type) {
case shader::ShaderCreateInfo::Resource::BindType::IMAGE:
return texture_get(binding + image_offset_);
/* Not really nice, but the binding namespace between OpenGL and Vulkan don't match. To fix
* this we need to check if one of both cases return a binding.
* TODO: we might want to introduce a different API to fix this. */
return texture_get((binding >= image_offset_) ? binding : binding + image_offset_);
case shader::ShaderCreateInfo::Resource::BindType::SAMPLER:
return texture_get(binding);
case shader::ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER: