diff --git a/src/vulkan/runtime/vk_cmd_enqueue.c b/src/vulkan/runtime/vk_cmd_enqueue.c index b54f90edbb6..1cb91e1cc4c 100644 --- a/src/vulkan/runtime/vk_cmd_enqueue.c +++ b/src/vulkan/runtime/vk_cmd_enqueue.c @@ -25,6 +25,7 @@ #include "vk_alloc.h" #include "vk_cmd_enqueue_entrypoints.h" #include "vk_command_buffer.h" +#include "vk_device.h" #include "vk_util.h" VKAPI_ATTR void VKAPI_CALL @@ -194,3 +195,70 @@ vk_cmd_enqueue_CmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, } } } + +static void +unref_pipeline_layout(struct vk_cmd_queue *queue, + struct vk_cmd_queue_entry *cmd) +{ + struct vk_command_buffer *cmd_buffer = + container_of(queue, struct vk_command_buffer, cmd_queue); + struct vk_device *device = cmd_buffer->base.device; + + assert(cmd->type == VK_CMD_BIND_DESCRIPTOR_SETS); + + device->unref_pipeline_layout(device, cmd->u.bind_descriptor_sets.layout); +} + +VKAPI_ATTR void VKAPI_CALL +vk_cmd_enqueue_CmdBindDescriptorSets(VkCommandBuffer commandBuffer, + VkPipelineBindPoint pipelineBindPoint, + VkPipelineLayout layout, + uint32_t firstSet, + uint32_t descriptorSetCount, + const VkDescriptorSet* pDescriptorSets, + uint32_t dynamicOffsetCount, + const uint32_t *pDynamicOffsets) +{ + VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); + struct vk_device *device = cmd_buffer->base.device; + + struct vk_cmd_queue_entry *cmd = + vk_zalloc(cmd_buffer->cmd_queue.alloc, sizeof(*cmd), 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!cmd) + return; + + cmd->type = VK_CMD_BIND_DESCRIPTOR_SETS; + list_addtail(&cmd->cmd_link, &cmd_buffer->cmd_queue.cmds); + + /* We need to hold a reference to the descriptor set as long as this + * command is in the queue. Otherwise, it may get deleted out from under + * us before the command is replayed. + */ + device->ref_pipeline_layout(device, layout); + cmd->u.bind_descriptor_sets.layout = layout; + cmd->driver_free_cb = unref_pipeline_layout; + + cmd->u.bind_descriptor_sets.pipeline_bind_point = pipelineBindPoint; + cmd->u.bind_descriptor_sets.first_set = firstSet; + cmd->u.bind_descriptor_sets.descriptor_set_count = descriptorSetCount; + if (pDescriptorSets) { + cmd->u.bind_descriptor_sets.descriptor_sets = + vk_zalloc(cmd_buffer->cmd_queue.alloc, + sizeof(*cmd->u.bind_descriptor_sets.descriptor_sets) * descriptorSetCount, 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + + memcpy(cmd->u.bind_descriptor_sets.descriptor_sets, pDescriptorSets, + sizeof(*cmd->u.bind_descriptor_sets.descriptor_sets) * descriptorSetCount); + } + cmd->u.bind_descriptor_sets.dynamic_offset_count = dynamicOffsetCount; + if (pDynamicOffsets) { + cmd->u.bind_descriptor_sets.dynamic_offsets = + vk_zalloc(cmd_buffer->cmd_queue.alloc, + sizeof(*cmd->u.bind_descriptor_sets.dynamic_offsets) * dynamicOffsetCount, 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + + memcpy(cmd->u.bind_descriptor_sets.dynamic_offsets, pDynamicOffsets, + sizeof(*cmd->u.bind_descriptor_sets.dynamic_offsets) * dynamicOffsetCount); + } +} diff --git a/src/vulkan/runtime/vk_device.h b/src/vulkan/runtime/vk_device.h index 9dced009cc8..b649e2e195d 100644 --- a/src/vulkan/runtime/vk_device.h +++ b/src/vulkan/runtime/vk_device.h @@ -96,6 +96,22 @@ struct vk_device { bool signal_memory, struct vk_sync **sync_out); + /** Increments the reference count on a pipeline layout + * + * This is required for vk_enqueue_CmdBindDescriptorSets() to avoid + * use-after-free problems with pipeline layouts. If you're not using + * the command queue, you can ignore this. + */ + void (*ref_pipeline_layout)(struct vk_device *device, + VkPipelineLayout layout); + + /** Decrements the reference count on a pipeline layout + * + * See ref_pipeline_layout above. + */ + void (*unref_pipeline_layout)(struct vk_device *device, + VkPipelineLayout layout); + /* Set by vk_device_set_drm_fd() */ int drm_fd;