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