| /* | |
| * 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 |