VkDescriptorSetLayout* pSetLayout)
{
ANV_FROM_HANDLE(anv_device, device, _device);
- struct anv_descriptor_set_layout *set_layout;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
immutable_sampler_count += pCreateInfo->pBindings[j].descriptorCount;
}
- size_t size = sizeof(struct anv_descriptor_set_layout) +
- (max_binding + 1) * sizeof(set_layout->binding[0]) +
- immutable_sampler_count * sizeof(struct anv_sampler *);
+ struct anv_descriptor_set_layout *set_layout;
+ struct anv_descriptor_set_binding_layout *bindings;
+ struct anv_sampler **samplers;
- set_layout = anv_alloc2(&device->alloc, pAllocator, size, 8,
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
- if (!set_layout)
- return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+ /* We need to allocate decriptor set layouts off the device allocator
+ * with DEVICE scope because they are reference counted and may not be
+ * destroyed when vkDestroyDescriptorSetLayout is called.
+ */
+ ANV_MULTIALLOC(ma);
+ anv_multialloc_add(&ma, &set_layout, 1);
+ anv_multialloc_add(&ma, &bindings, max_binding + 1);
+ anv_multialloc_add(&ma, &samplers, immutable_sampler_count);
- /* We just allocate all the samplers at the end of the struct */
- struct anv_sampler **samplers =
- (struct anv_sampler **)&set_layout->binding[max_binding + 1];
+ if (!anv_multialloc_alloc(&ma, &device->alloc,
+ VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
memset(set_layout, 0, sizeof(*set_layout));
+ set_layout->ref_cnt = 1;
set_layout->binding_count = max_binding + 1;
for (uint32_t b = 0; b <= max_binding; b++) {
if (binding == NULL)
continue;
- assert(binding->descriptorCount > 0);
+ if (binding->descriptorCount == 0)
+ continue;
+
#ifndef NDEBUG
set_layout->binding[b].type = binding->descriptorType;
#endif
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_descriptor_set_layout, set_layout, _set_layout);
- anv_free2(&device->alloc, pAllocator, set_layout);
+ if (!set_layout)
+ return;
+
+ anv_descriptor_set_layout_unref(device, set_layout);
}
static void
/*
* Pipeline layouts. These have nothing to do with the pipeline. They are
- * just muttiple descriptor set layouts pasted together
+ * just multiple descriptor set layouts pasted together
*/
VkResult anv_CreatePipelineLayout(
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO);
- layout = anv_alloc2(&device->alloc, pAllocator, sizeof(*layout), 8,
+ layout = vk_alloc2(&device->alloc, pAllocator, sizeof(*layout), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (layout == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
ANV_FROM_HANDLE(anv_descriptor_set_layout, set_layout,
pCreateInfo->pSetLayouts[set]);
layout->set[set].layout = set_layout;
+ anv_descriptor_set_layout_ref(set_layout);
layout->set[set].dynamic_offset_start = dynamic_offset_count;
for (uint32_t b = 0; b < set_layout->binding_count; b++) {
}
}
- struct mesa_sha1 *ctx = _mesa_sha1_init();
+ struct mesa_sha1 ctx;
+ _mesa_sha1_init(&ctx);
for (unsigned s = 0; s < layout->num_sets; s++) {
- sha1_update_descriptor_set_layout(ctx, layout->set[s].layout);
- _mesa_sha1_update(ctx, &layout->set[s].dynamic_offset_start,
+ sha1_update_descriptor_set_layout(&ctx, layout->set[s].layout);
+ _mesa_sha1_update(&ctx, &layout->set[s].dynamic_offset_start,
sizeof(layout->set[s].dynamic_offset_start));
}
- _mesa_sha1_update(ctx, &layout->num_sets, sizeof(layout->num_sets));
+ _mesa_sha1_update(&ctx, &layout->num_sets, sizeof(layout->num_sets));
for (unsigned s = 0; s < MESA_SHADER_STAGES; s++) {
- _mesa_sha1_update(ctx, &layout->stage[s].has_dynamic_offsets,
+ _mesa_sha1_update(&ctx, &layout->stage[s].has_dynamic_offsets,
sizeof(layout->stage[s].has_dynamic_offsets));
}
- _mesa_sha1_final(ctx, layout->sha1);
+ _mesa_sha1_final(&ctx, layout->sha1);
*pPipelineLayout = anv_pipeline_layout_to_handle(layout);
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_pipeline_layout, pipeline_layout, _pipelineLayout);
- anv_free2(&device->alloc, pAllocator, pipeline_layout);
+ if (!pipeline_layout)
+ return;
+
+ for (uint32_t i = 0; i < pipeline_layout->num_sets; i++)
+ anv_descriptor_set_layout_unref(device, pipeline_layout->set[i].layout);
+
+ vk_free2(&device->alloc, pAllocator, pipeline_layout);
}
/*
}
}
- const size_t size =
- sizeof(*pool) +
+ const size_t pool_size =
pCreateInfo->maxSets * sizeof(struct anv_descriptor_set) +
descriptor_count * sizeof(struct anv_descriptor) +
buffer_count * sizeof(struct anv_buffer_view);
+ const size_t total_size = sizeof(*pool) + pool_size;
- pool = anv_alloc2(&device->alloc, pAllocator, size, 8,
+ pool = vk_alloc2(&device->alloc, pAllocator, total_size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!pool)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
- pool->size = size;
+ pool->size = pool_size;
pool->next = 0;
pool->free_list = EMPTY;
anv_state_stream_init(&pool->surface_state_stream,
- &device->surface_state_block_pool);
+ &device->surface_state_pool, 4096);
pool->surface_state_free_list = NULL;
*pDescriptorPool = anv_descriptor_pool_to_handle(pool);
ANV_FROM_HANDLE(anv_device, device, _device);
ANV_FROM_HANDLE(anv_descriptor_pool, pool, _pool);
+ if (!pool)
+ return;
+
anv_state_stream_finish(&pool->surface_state_stream);
- anv_free2(&device->alloc, pAllocator, pool);
+ vk_free2(&device->alloc, pAllocator, pool);
}
VkResult anv_ResetDescriptorPool(
pool->free_list = EMPTY;
anv_state_stream_finish(&pool->surface_state_stream);
anv_state_stream_init(&pool->surface_state_stream,
- &device->surface_state_block_pool);
+ &device->surface_state_pool, 4096);
pool->surface_state_free_list = NULL;
return VK_SUCCESS;
uint32_t size;
};
-static size_t
-layout_size(const struct anv_descriptor_set_layout *layout)
+size_t
+anv_descriptor_set_layout_size(const struct anv_descriptor_set_layout *layout)
{
return
sizeof(struct anv_descriptor_set) +
layout->buffer_count * sizeof(struct anv_buffer_view);
}
+size_t
+anv_descriptor_set_binding_layout_get_hw_size(const struct anv_descriptor_set_binding_layout *binding)
+{
+ if (!binding->immutable_samplers)
+ return binding->array_size;
+
+ uint32_t total_plane_count = 0;
+ for (uint32_t i = 0; i < binding->array_size; i++)
+ total_plane_count += binding->immutable_samplers[i]->n_planes;
+
+ return total_plane_count;
+}
+
struct surface_state_free_list_entry {
void *next;
- uint32_t offset;
+ struct anv_state state;
};
VkResult
anv_descriptor_set_create(struct anv_device *device,
struct anv_descriptor_pool *pool,
- const struct anv_descriptor_set_layout *layout,
+ struct anv_descriptor_set_layout *layout,
struct anv_descriptor_set **out_set)
{
struct anv_descriptor_set *set;
- const size_t size = layout_size(layout);
+ const size_t size = anv_descriptor_set_layout_size(layout);
set = NULL;
if (size <= pool->size - pool->next) {
}
}
- if (set == NULL)
- return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+ if (set == NULL) {
+ if (pool->free_list != EMPTY) {
+ return vk_error(VK_ERROR_FRAGMENTED_POOL);
+ } else {
+ return vk_error(VK_ERROR_OUT_OF_POOL_MEMORY_KHR);
+ }
+ }
- set->size = size;
set->layout = layout;
+ anv_descriptor_set_layout_ref(layout);
+
+ set->size = size;
set->buffer_views =
(struct anv_buffer_view *) &set->descriptors[layout->size];
set->buffer_count = layout->buffer_count;
struct anv_state state;
if (entry) {
- state.map = entry;
- state.offset = entry->offset;
- state.alloc_size = 64;
+ state = entry->state;
pool->surface_state_free_list = entry->next;
+ assert(state.alloc_size == 64);
} else {
state = anv_state_stream_alloc(&pool->surface_state_stream, 64, 64);
}
struct anv_descriptor_pool *pool,
struct anv_descriptor_set *set)
{
+ anv_descriptor_set_layout_unref(device, set->layout);
+
/* Put the buffer view surface state back on the free list. */
for (uint32_t b = 0; b < set->buffer_count; b++) {
struct surface_state_free_list_entry *entry =
set->buffer_views[b].surface_state.map;
entry->next = pool->surface_state_free_list;
+ entry->state = set->buffer_views[b].surface_state;
pool->surface_state_free_list = entry;
}
for (uint32_t i = 0; i < count; i++) {
ANV_FROM_HANDLE(anv_descriptor_set, set, pDescriptorSets[i]);
+ if (!set)
+ continue;
+
anv_descriptor_set_destroy(device, pool, set);
}
return VK_SUCCESS;
}
+void
+anv_descriptor_set_write_image_view(struct anv_descriptor_set *set,
+ const struct gen_device_info * const devinfo,
+ const VkDescriptorImageInfo * const info,
+ VkDescriptorType type,
+ uint32_t binding,
+ uint32_t element)
+{
+ const struct anv_descriptor_set_binding_layout *bind_layout =
+ &set->layout->binding[binding];
+ struct anv_descriptor *desc =
+ &set->descriptors[bind_layout->descriptor_index + element];
+ struct anv_image_view *image_view = NULL;
+ struct anv_sampler *sampler = NULL;
+
+ assert(type == bind_layout->type);
+
+ switch (type) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ sampler = anv_sampler_from_handle(info->sampler);
+ break;
+
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ image_view = anv_image_view_from_handle(info->imageView);
+ sampler = anv_sampler_from_handle(info->sampler);
+ break;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ image_view = anv_image_view_from_handle(info->imageView);
+ break;
+
+ default:
+ unreachable("invalid descriptor type");
+ }
+
+ /* If this descriptor has an immutable sampler, we don't want to stomp on
+ * it.
+ */
+ sampler = bind_layout->immutable_samplers ?
+ bind_layout->immutable_samplers[element] :
+ sampler;
+
+ *desc = (struct anv_descriptor) {
+ .type = type,
+ .layout = info->imageLayout,
+ .image_view = image_view,
+ .sampler = sampler,
+ };
+}
+
+void
+anv_descriptor_set_write_buffer_view(struct anv_descriptor_set *set,
+ VkDescriptorType type,
+ struct anv_buffer_view *buffer_view,
+ uint32_t binding,
+ uint32_t element)
+{
+ const struct anv_descriptor_set_binding_layout *bind_layout =
+ &set->layout->binding[binding];
+ struct anv_descriptor *desc =
+ &set->descriptors[bind_layout->descriptor_index + element];
+
+ assert(type == bind_layout->type);
+
+ *desc = (struct anv_descriptor) {
+ .type = type,
+ .buffer_view = buffer_view,
+ };
+}
+
+void
+anv_descriptor_set_write_buffer(struct anv_descriptor_set *set,
+ struct anv_device *device,
+ struct anv_state_stream *alloc_stream,
+ VkDescriptorType type,
+ struct anv_buffer *buffer,
+ uint32_t binding,
+ uint32_t element,
+ VkDeviceSize offset,
+ VkDeviceSize range)
+{
+ const struct anv_descriptor_set_binding_layout *bind_layout =
+ &set->layout->binding[binding];
+ struct anv_descriptor *desc =
+ &set->descriptors[bind_layout->descriptor_index + element];
+
+ assert(type == bind_layout->type);
+
+ if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
+ type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC) {
+ *desc = (struct anv_descriptor) {
+ .type = type,
+ .buffer = buffer,
+ .offset = offset,
+ .range = range,
+ };
+ } else {
+ struct anv_buffer_view *bview =
+ &set->buffer_views[bind_layout->buffer_index + element];
+
+ bview->format = anv_isl_format_for_descriptor_type(type);
+ bview->bo = buffer->bo;
+ bview->offset = buffer->offset + offset;
+ bview->range = anv_buffer_get_range(buffer, offset, range);
+
+ /* If we're writing descriptors through a push command, we need to
+ * allocate the surface state from the command buffer. Otherwise it will
+ * be allocated by the descriptor pool when calling
+ * vkAllocateDescriptorSets. */
+ if (alloc_stream)
+ bview->surface_state = anv_state_stream_alloc(alloc_stream, 64, 64);
+
+ anv_fill_buffer_surface_state(device, bview->surface_state,
+ bview->format,
+ bview->offset, bview->range, 1);
+
+ *desc = (struct anv_descriptor) {
+ .type = type,
+ .buffer_view = bview,
+ };
+ }
+}
+
void anv_UpdateDescriptorSets(
VkDevice _device,
uint32_t descriptorWriteCount,
for (uint32_t i = 0; i < descriptorWriteCount; i++) {
const VkWriteDescriptorSet *write = &pDescriptorWrites[i];
ANV_FROM_HANDLE(anv_descriptor_set, set, write->dstSet);
- const struct anv_descriptor_set_binding_layout *bind_layout =
- &set->layout->binding[write->dstBinding];
- struct anv_descriptor *desc =
- &set->descriptors[bind_layout->descriptor_index];
- desc += write->dstArrayElement;
-
- assert(write->descriptorType == bind_layout->type);
switch (write->descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER:
- for (uint32_t j = 0; j < write->descriptorCount; j++) {
- ANV_FROM_HANDLE(anv_sampler, sampler,
- write->pImageInfo[j].sampler);
-
- desc[j] = (struct anv_descriptor) {
- .type = VK_DESCRIPTOR_TYPE_SAMPLER,
- .sampler = sampler,
- };
- }
- break;
-
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
- for (uint32_t j = 0; j < write->descriptorCount; j++) {
- ANV_FROM_HANDLE(anv_image_view, iview,
- write->pImageInfo[j].imageView);
- ANV_FROM_HANDLE(anv_sampler, sampler,
- write->pImageInfo[j].sampler);
-
- desc[j].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- desc[j].image_view = iview;
-
- /* If this descriptor has an immutable sampler, we don't want
- * to stomp on it.
- */
- if (sampler)
- desc[j].sampler = sampler;
- }
- break;
-
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
for (uint32_t j = 0; j < write->descriptorCount; j++) {
- ANV_FROM_HANDLE(anv_image_view, iview,
- write->pImageInfo[j].imageView);
-
- desc[j] = (struct anv_descriptor) {
- .type = write->descriptorType,
- .image_view = iview,
- };
+ anv_descriptor_set_write_image_view(set, &device->info,
+ write->pImageInfo + j,
+ write->descriptorType,
+ write->dstBinding,
+ write->dstArrayElement + j);
}
break;
ANV_FROM_HANDLE(anv_buffer_view, bview,
write->pTexelBufferView[j]);
- desc[j] = (struct anv_descriptor) {
- .type = write->descriptorType,
- .buffer_view = bview,
- };
+ anv_descriptor_set_write_buffer_view(set,
+ write->descriptorType,
+ bview,
+ write->dstBinding,
+ write->dstArrayElement + j);
}
break;
- case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
- anv_finishme("input attachments not implemented");
- break;
-
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
ANV_FROM_HANDLE(anv_buffer, buffer, write->pBufferInfo[j].buffer);
assert(buffer);
- struct anv_buffer_view *view =
- &set->buffer_views[bind_layout->buffer_index];
- view += write->dstArrayElement + j;
-
- view->format =
- anv_isl_format_for_descriptor_type(write->descriptorType);
- view->bo = buffer->bo;
- view->offset = buffer->offset + write->pBufferInfo[j].offset;
-
- /* For buffers with dynamic offsets, we use the full possible
- * range in the surface state and do the actual range-checking
- * in the shader.
- */
- if (bind_layout->dynamic_offset_index >= 0 ||
- write->pBufferInfo[j].range == VK_WHOLE_SIZE)
- view->range = buffer->size - write->pBufferInfo[j].offset;
- else
- view->range = write->pBufferInfo[j].range;
-
- anv_fill_buffer_surface_state(device, view->surface_state,
- view->format,
- view->offset, view->range, 1);
-
- desc[j] = (struct anv_descriptor) {
- .type = write->descriptorType,
- .buffer_view = view,
- };
-
+ anv_descriptor_set_write_buffer(set,
+ device,
+ NULL,
+ write->descriptorType,
+ buffer,
+ write->dstBinding,
+ write->dstArrayElement + j,
+ write->pBufferInfo[j].offset,
+ write->pBufferInfo[j].range);
}
+ break;
default:
break;
for (uint32_t i = 0; i < descriptorCopyCount; i++) {
const VkCopyDescriptorSet *copy = &pDescriptorCopies[i];
- ANV_FROM_HANDLE(anv_descriptor_set, src, copy->dstSet);
+ ANV_FROM_HANDLE(anv_descriptor_set, src, copy->srcSet);
ANV_FROM_HANDLE(anv_descriptor_set, dst, copy->dstSet);
const struct anv_descriptor_set_binding_layout *src_layout =
dst_desc[j] = src_desc[j];
}
}
+
+/*
+ * Descriptor update templates.
+ */
+
+void
+anv_descriptor_set_write_template(struct anv_descriptor_set *set,
+ struct anv_device *device,
+ struct anv_state_stream *alloc_stream,
+ const struct anv_descriptor_update_template *template,
+ const void *data)
+{
+ const struct anv_descriptor_set_layout *layout = set->layout;
+
+ for (uint32_t i = 0; i < template->entry_count; i++) {
+ const struct anv_descriptor_template_entry *entry =
+ &template->entries[i];
+ const struct anv_descriptor_set_binding_layout *bind_layout =
+ &layout->binding[entry->binding];
+ struct anv_descriptor *desc = &set->descriptors[bind_layout->descriptor_index];
+ desc += entry->array_element;
+
+ switch (entry->type) {
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ for (uint32_t j = 0; j < entry->array_count; j++) {
+ const VkDescriptorImageInfo *info =
+ data + entry->offset + j * entry->stride;
+ anv_descriptor_set_write_image_view(set, &device->info,
+ info, entry->type,
+ entry->binding,
+ entry->array_element + j);
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ for (uint32_t j = 0; j < entry->array_count; j++) {
+ const VkBufferView *_bview =
+ data + entry->offset + j * entry->stride;
+ ANV_FROM_HANDLE(anv_buffer_view, bview, *_bview);
+
+ anv_descriptor_set_write_buffer_view(set,
+ entry->type,
+ bview,
+ entry->binding,
+ entry->array_element + j);
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ for (uint32_t j = 0; j < entry->array_count; j++) {
+ const VkDescriptorBufferInfo *info =
+ data + entry->offset + j * entry->stride;
+ ANV_FROM_HANDLE(anv_buffer, buffer, info->buffer);
+
+ anv_descriptor_set_write_buffer(set,
+ device,
+ alloc_stream,
+ entry->type,
+ buffer,
+ entry->binding,
+ entry->array_element + j,
+ info->offset, info->range);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+VkResult anv_CreateDescriptorUpdateTemplateKHR(
+ VkDevice _device,
+ const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ struct anv_descriptor_update_template *template;
+
+ size_t size = sizeof(*template) +
+ pCreateInfo->descriptorUpdateEntryCount * sizeof(template->entries[0]);
+ template = vk_alloc2(&device->alloc, pAllocator, size, 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (template == NULL)
+ return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+ template->bind_point = pCreateInfo->pipelineBindPoint;
+
+ if (pCreateInfo->templateType == VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR)
+ template->set = pCreateInfo->set;
+
+ template->entry_count = pCreateInfo->descriptorUpdateEntryCount;
+ for (uint32_t i = 0; i < template->entry_count; i++) {
+ const VkDescriptorUpdateTemplateEntryKHR *pEntry =
+ &pCreateInfo->pDescriptorUpdateEntries[i];
+
+ template->entries[i] = (struct anv_descriptor_template_entry) {
+ .type = pEntry->descriptorType,
+ .binding = pEntry->dstBinding,
+ .array_element = pEntry->dstArrayElement,
+ .array_count = pEntry->descriptorCount,
+ .offset = pEntry->offset,
+ .stride = pEntry->stride,
+ };
+ }
+
+ *pDescriptorUpdateTemplate =
+ anv_descriptor_update_template_to_handle(template);
+
+ return VK_SUCCESS;
+}
+
+void anv_DestroyDescriptorUpdateTemplateKHR(
+ VkDevice _device,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ const VkAllocationCallbacks* pAllocator)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_descriptor_update_template, template,
+ descriptorUpdateTemplate);
+
+ vk_free2(&device->alloc, pAllocator, template);
+}
+
+void anv_UpdateDescriptorSetWithTemplateKHR(
+ VkDevice _device,
+ VkDescriptorSet descriptorSet,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ const void* pData)
+{
+ ANV_FROM_HANDLE(anv_device, device, _device);
+ ANV_FROM_HANDLE(anv_descriptor_set, set, descriptorSet);
+ ANV_FROM_HANDLE(anv_descriptor_update_template, template,
+ descriptorUpdateTemplate);
+
+ anv_descriptor_set_write_template(set, device, NULL, template, pData);
+}