From e6c75bcd9c549721a6717ffdf7026e80e6f153dc Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 28 Jun 2022 11:03:42 -0500 Subject: [PATCH] vulkan: Add a common implementation of pipeline layouts Reviewed-by: Lionel Landwerlin Reviewed-by: Jesse Natalie Reviewed-by: Boris Brezillon Part-of: --- src/vulkan/runtime/meson.build | 2 + src/vulkan/runtime/vk_pipeline_layout.c | 141 ++++++++++++++++++++++++ src/vulkan/runtime/vk_pipeline_layout.h | 113 +++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 src/vulkan/runtime/vk_pipeline_layout.c create mode 100644 src/vulkan/runtime/vk_pipeline_layout.h diff --git a/src/vulkan/runtime/meson.build b/src/vulkan/runtime/meson.build index acbe34ece7c..1f5a9633190 100644 --- a/src/vulkan/runtime/meson.build +++ b/src/vulkan/runtime/meson.build @@ -64,6 +64,8 @@ vulkan_runtime_files = files( 'vk_pipeline_cache.h', 'vk_physical_device.c', 'vk_physical_device.h', + 'vk_pipeline_layout.c', + 'vk_pipeline_layout.h', 'vk_queue.c', 'vk_queue.h', 'vk_render_pass.c', diff --git a/src/vulkan/runtime/vk_pipeline_layout.c b/src/vulkan/runtime/vk_pipeline_layout.c new file mode 100644 index 00000000000..4ea1672376c --- /dev/null +++ b/src/vulkan/runtime/vk_pipeline_layout.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2022 Collabora Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_pipeline_layout.h" + +#include "vk_alloc.h" +#include "vk_common_entrypoints.h" +#include "vk_descriptor_set_layout.h" +#include "vk_device.h" +#include "vk_log.h" + +#include "util/mesa-sha1.h" + +static void +vk_pipeline_layout_init(struct vk_device *device, + struct vk_pipeline_layout *layout, + const VkPipelineLayoutCreateInfo *pCreateInfo) +{ + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO); + assert(pCreateInfo->setLayoutCount <= VK_MESA_PIPELINE_LAYOUT_MAX_SETS); + + vk_object_base_init(device, &layout->base, VK_OBJECT_TYPE_PIPELINE_LAYOUT); + + layout->ref_cnt = 1; + layout->create_flags = pCreateInfo->flags; + layout->set_count = pCreateInfo->setLayoutCount; + layout->destroy = vk_pipeline_layout_destroy; + + for (uint32_t s = 0; s < pCreateInfo->setLayoutCount; s++) { + VK_FROM_HANDLE(vk_descriptor_set_layout, set_layout, + pCreateInfo->pSetLayouts[s]); + + if (set_layout == NULL) { + assert(layout->create_flags & + VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT); + continue; + } + + layout->set_layouts[s] = vk_descriptor_set_layout_ref(set_layout); + } +} + +void * +vk_pipeline_layout_zalloc(struct vk_device *device, size_t size, + const VkPipelineLayoutCreateInfo *pCreateInfo) +{ + /* Because we're reference counting and lifetimes may not be what the + * client expects, these have to be allocated off the device and not as + * their own object. + */ + struct vk_pipeline_layout *layout = + vk_zalloc(&device->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (layout == NULL) + return NULL; + + vk_pipeline_layout_init(device, layout, pCreateInfo); + return layout; +} + +void * +vk_pipeline_layout_multizalloc(struct vk_device *device, + struct vk_multialloc *ma, + const VkPipelineLayoutCreateInfo *pCreateInfo) +{ + struct vk_pipeline_layout *layout = + vk_multialloc_zalloc(ma, &device->alloc, + VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); + if (layout == NULL) + return NULL; + + vk_pipeline_layout_init(device, layout, pCreateInfo); + return layout; +} + + +VKAPI_ATTR VkResult VKAPI_CALL +vk_common_CreatePipelineLayout(VkDevice _device, + const VkPipelineLayoutCreateInfo *pCreateInfo, + UNUSED const VkAllocationCallbacks *pAllocator, + VkPipelineLayout *pPipelineLayout) +{ + VK_FROM_HANDLE(vk_device, device, _device); + + struct vk_pipeline_layout *layout = + vk_pipeline_layout_zalloc(device, sizeof(struct vk_pipeline_layout), + pCreateInfo); + if (layout == NULL) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + *pPipelineLayout = vk_pipeline_layout_to_handle(layout); + + return VK_SUCCESS; +} + +void +vk_pipeline_layout_destroy(struct vk_device *device, + struct vk_pipeline_layout *layout) +{ + assert(layout && layout->ref_cnt == 0); + + for (uint32_t s = 0; s < layout->set_count; s++) { + if (layout->set_layouts[s] != NULL) + vk_descriptor_set_layout_unref(device, (void *)layout->set_layouts[s]); + } + + vk_object_free(device, NULL, layout); +} + +VKAPI_ATTR void VKAPI_CALL +vk_common_DestroyPipelineLayout(VkDevice _device, + VkPipelineLayout pipelineLayout, + UNUSED const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_device, device, _device); + VK_FROM_HANDLE(vk_pipeline_layout, layout, pipelineLayout); + + if (layout == NULL) + return; + + vk_pipeline_layout_unref(device, layout); +} diff --git a/src/vulkan/runtime/vk_pipeline_layout.h b/src/vulkan/runtime/vk_pipeline_layout.h new file mode 100644 index 00000000000..5f7f04cf0c5 --- /dev/null +++ b/src/vulkan/runtime/vk_pipeline_layout.h @@ -0,0 +1,113 @@ +/* + * Copyright © 2022 Collabora Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef VK_PIPELINE_LAYOUT_H +#define VK_PIPELINE_LAYOUT_H + +#include "vk_object.h" + +#include "util/u_atomic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct vk_descriptor_set_layout; + +#define VK_MESA_PIPELINE_LAYOUT_MAX_SETS 32 + +struct vk_pipeline_layout { + struct vk_object_base base; + + /** Reference count + * + * It's often necessary to store a pointer to the descriptor set layout in + * the descriptor so that any entrypoint which has access to a descriptor + * set also has the layout. While layouts are often passed into various + * entrypoints, they're notably missing from vkUpdateDescriptorSets(). In + * order to implement descriptor writes, you either need to stash a pointer + * to the descriptor set layout in the descriptor set or you need to copy + * all of the relevant information. Storing a pointer is a lot cheaper. + * + * Because descriptor set layout lifetimes and descriptor set lifetimes are + * not guaranteed to coincide, we have to reference count if we're going to + * do this. + */ + uint32_t ref_cnt; + + /** VkPipelineLayoutCreateInfo::flags */ + VkPipelineLayoutCreateFlagBits create_flags; + + /** Number of descriptor set layouts in this pipeline layout */ + uint32_t set_count; + + /** Array of pointers to descriptor set layouts, indexed by set index */ + const struct vk_descriptor_set_layout *set_layouts[VK_MESA_PIPELINE_LAYOUT_MAX_SETS]; + + /** Destroy callback + * + * Will be initially set to vk_pipeline_layout_destroy() but may be set to + * a driver-specific callback which does driver-specific clean-up and then + * calls vk_pipeline_layout_destroy(). + */ + void (*destroy)(struct vk_device *device, + struct vk_pipeline_layout *layout); +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(vk_pipeline_layout, base, VkPipelineLayout, + VK_OBJECT_TYPE_PIPELINE_LAYOUT); + +void * +vk_pipeline_layout_zalloc(struct vk_device *device, size_t size, + const VkPipelineLayoutCreateInfo *pCreateInfo); + +void * +vk_pipeline_layout_multizalloc(struct vk_device *device, + struct vk_multialloc *ma, + const VkPipelineLayoutCreateInfo *pCreateInfo); + +void vk_pipeline_layout_destroy(struct vk_device *device, + struct vk_pipeline_layout *layout); + +static inline struct vk_pipeline_layout * +vk_pipeline_layout_ref(struct vk_pipeline_layout *layout) +{ + assert(layout && layout->ref_cnt >= 1); + p_atomic_inc(&layout->ref_cnt); + return layout; +} + +static inline void +vk_pipeline_layout_unref(struct vk_device *device, + struct vk_pipeline_layout *layout) +{ + assert(layout && layout->ref_cnt >= 1); + if (p_atomic_dec_zero(&layout->ref_cnt)) + layout->destroy(device, layout); +} + +#ifdef __cplusplus +} +#endif + +#endif /* VK_PIPELINE_LAYOUT_H */ +