blob: 8d99ee3839e1fe2923e44078951bb64f3d772511 [file]
/*
* Copyright 2023 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/graphite/vk/VulkanDescriptorPool.h"
#include "include/private/SkTArray.h"
#include "src/gpu/graphite/vk/VulkanGraphiteUtils.h"
#include "src/gpu/graphite/vk/VulkanSharedContext.h"
namespace skgpu::graphite {
sk_sp<VulkanDescriptorPool> VulkanDescriptorPool::Make(
const VulkanSharedContext* context,
SkSpan<const DescriptorData> requestedDescCounts,
VkDescriptorSetLayout layout,
uint32_t numSets) {
if (requestedDescCounts.empty() || numSets == 0) {
// Note: On failure, we do not destroy `layout` here or below because the caller
// (VulkanResourceProvider) retains ownership and destroys `layout` if pool creation fails.
// VulkanDescriptorPool only takes ownership of `layout` on success.
return nullptr;
}
// Multiple bindings within a descriptor set may request the same descriptor type (e.g. multiple
// storage buffers in compute steps). Consolidate identical descriptor types so each
// VkDescriptorType appears at most once in poolSizes. This guarantees that poolSizes contains
// at most kDescriptorTypeCount entries. We also validate cumulative per-set descriptor counts
// against kMaxNumDescriptors to prevent limits from being evaded across bindings.
skia_private::STArray<kDescriptorTypeCount, VkDescriptorPoolSize> poolSizes;
for (const DescriptorData& desc : requestedDescCounts) {
SkASSERT(desc.fCount > 0 && desc.fCount <= kMaxNumDescriptors);
VkDescriptorType descType = DsTypeEnumToVkDs(desc.fType);
VkDescriptorPoolSize* entry = nullptr;
for (auto& existing : poolSizes) {
if (existing.type == descType) {
entry = &existing;
break;
}
}
if (!entry) {
entry = &poolSizes.push_back();
entry->type = descType;
entry->descriptorCount = 0;
}
entry->descriptorCount += desc.fCount;
}
for (auto& poolSize : poolSizes) {
if (poolSize.descriptorCount > kMaxNumDescriptors) {
SkDebugf("The cumulative number of descriptors requested (%u) for type %d "
"exceeds the maximum allowed per set (%d).\n",
poolSize.descriptorCount,
poolSize.type,
kMaxNumDescriptors);
return nullptr;
}
poolSize.descriptorCount *= numSets;
}
VkDescriptorPoolCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
createInfo.maxSets = numSets;
createInfo.poolSizeCount = SkTo<uint32_t>(poolSizes.size());
createInfo.pPoolSizes = poolSizes.data();
VkDescriptorPool pool;
VkResult result;
VULKAN_CALL_RESULT(context,
result,
CreateDescriptorPool(context->device(),
&createInfo,
/*const VkAllocationCallbacks*=*/nullptr,
&pool));
if (result != VK_SUCCESS) {
return nullptr;
}
return sk_sp<VulkanDescriptorPool>(new VulkanDescriptorPool(context, pool, layout));
}
VulkanDescriptorPool::VulkanDescriptorPool(const VulkanSharedContext* context,
VkDescriptorPool pool,
VkDescriptorSetLayout layout)
: fSharedContext(context)
, fDescPool(pool)
, fDescSetLayout(layout) {}
VulkanDescriptorPool::~VulkanDescriptorPool() {
// Destroying the VkDescriptorPool will automatically free and delete any VkDescriptorSets
// allocated from the pool.
VULKAN_CALL(fSharedContext->interface(),
DestroyDescriptorPool(fSharedContext->device(), fDescPool, nullptr));
if (fDescSetLayout != VK_NULL_HANDLE) {
VULKAN_CALL(fSharedContext->interface(),
DestroyDescriptorSetLayout(fSharedContext->device(), fDescSetLayout, nullptr));
fDescSetLayout = VK_NULL_HANDLE;
}
}
} // namespace skgpu::graphite