From e3eb3498c2246a7f23234a7e95750ca2cb4a5009 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 5 May 2020 19:44:16 +0200 Subject: [PATCH] vkd3d: Implement sparse binding. Signed-off-by: Philip Rebohle --- libs/vkd3d/command.c | 180 +++++++++++++++++++++++++++++++++++++ libs/vkd3d/vkd3d_private.h | 25 ++++++ 2 files changed, 205 insertions(+) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 207ba46b..97e650b5 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -6899,6 +6899,179 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu vkd3d_queue_release(command_queue->vkd3d_queue); } +static void d3d12_command_queue_bind_sparse(struct d3d12_command_queue *command_queue, + enum vkd3d_sparse_memory_bind_mode mode, struct d3d12_resource *dst_resource, + struct d3d12_resource *src_resource, unsigned int count, + struct vkd3d_sparse_memory_bind *bind_infos) +{ + VkSparseImageOpaqueMemoryBindInfo opaque_info; + const struct vkd3d_vk_device_procs *vk_procs; + VkSparseImageMemoryBind *image_binds = NULL; + VkSparseBufferMemoryBindInfo buffer_info; + VkSparseMemoryBind *memory_binds = NULL; + VkSparseImageMemoryBindInfo image_info; + VkBindSparseInfo bind_sparse_info; + unsigned int first_packed_tile; + struct vkd3d_queue *queue; + VkDeviceMemory vk_memory; + VkDeviceSize vk_offset; + unsigned int i, j, k; + VkQueue vk_queue; + VkResult vr; + + TRACE("queue %p, dst_resource %p, src_resource %p, count %u, bind_infos %p.\n", + command_queue, dst_resource, src_resource, count, bind_infos); + + vk_procs = &command_queue->device->vk_procs; + + bind_sparse_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; + bind_sparse_info.pNext = NULL; + bind_sparse_info.waitSemaphoreCount = 0; + bind_sparse_info.pWaitSemaphores = NULL; + bind_sparse_info.bufferBindCount = 0; + bind_sparse_info.pBufferBinds = NULL; + bind_sparse_info.imageOpaqueBindCount = 0; + bind_sparse_info.pImageOpaqueBinds = NULL; + bind_sparse_info.imageBindCount = 0; + bind_sparse_info.pImageBinds = NULL; + bind_sparse_info.signalSemaphoreCount = 0; + bind_sparse_info.pSignalSemaphores = NULL; + + first_packed_tile = dst_resource->sparse.tile_count; + + if (d3d12_resource_is_buffer(dst_resource)) + { + if (!(memory_binds = vkd3d_malloc(count * sizeof(*memory_binds)))) + { + ERR("Failed to allocate sparse memory bind info.\n"); + goto cleanup; + } + + buffer_info.buffer = dst_resource->u.vk_buffer; + buffer_info.bindCount = count; + buffer_info.pBinds = memory_binds; + + bind_sparse_info.bufferBindCount = 1; + bind_sparse_info.pBufferBinds = &buffer_info; + } + else + { + unsigned int opaque_bind_count = 0; + unsigned int image_bind_count = 0; + + if (dst_resource->sparse.packed_mips.NumPackedMips) + first_packed_tile = dst_resource->sparse.packed_mips.StartTileIndexInOverallResource; + + for (i = 0; i < count; i++) + { + const struct vkd3d_sparse_memory_bind *bind = &bind_infos[i]; + + if (bind->dst_tile < first_packed_tile) + image_bind_count++; + else + opaque_bind_count++; + } + + if (opaque_bind_count) + { + if (!(memory_binds = vkd3d_malloc(opaque_bind_count * sizeof(*memory_binds)))) + { + ERR("Failed to allocate sparse memory bind info.\n"); + goto cleanup; + } + + opaque_info.image = dst_resource->u.vk_image; + opaque_info.bindCount = opaque_bind_count; + opaque_info.pBinds = memory_binds; + + bind_sparse_info.imageOpaqueBindCount = 1; + bind_sparse_info.pImageOpaqueBinds = &opaque_info; + } + + if (image_bind_count) + { + if (!(image_binds = vkd3d_malloc(image_bind_count * sizeof(*image_binds)))) + { + ERR("Failed to allocate sparse memory bind info.\n"); + goto cleanup; + } + + image_info.image = dst_resource->u.vk_image; + image_info.bindCount = image_bind_count; + image_info.pBinds = image_binds; + + bind_sparse_info.imageBindCount = 1; + bind_sparse_info.pImageBinds = &image_info; + } + } + + for (i = 0, j = 0, k = 0; i < count; i++) + { + const struct vkd3d_sparse_memory_bind *bind = &bind_infos[i]; + struct d3d12_sparse_tile *tile = &dst_resource->sparse.tiles[bind->dst_tile]; + + if (mode == VKD3D_SPARSE_MEMORY_BIND_MODE_UPDATE) + { + vk_memory = bind->vk_memory; + vk_offset = bind->vk_offset; + } + else /* if (mode == VKD3D_SPARSE_MEMORY_BIND_MODE_COPY) */ + { + struct d3d12_sparse_tile *src_tile = &src_resource->sparse.tiles[bind->src_tile]; + vk_memory = src_tile->vk_memory; + vk_offset = src_tile->vk_offset; + } + + if (d3d12_resource_is_texture(dst_resource) && bind->dst_tile < first_packed_tile) + { + VkSparseImageMemoryBind *vk_bind = &image_binds[j++]; + vk_bind->subresource = tile->u.image.subresource; + vk_bind->offset = tile->u.image.offset; + vk_bind->extent = tile->u.image.extent; + vk_bind->memory = vk_memory; + vk_bind->memoryOffset = vk_offset; + vk_bind->flags = 0; + } + else + { + VkSparseMemoryBind *vk_bind = &memory_binds[k++]; + vk_bind->resourceOffset = tile->u.buffer.offset; + vk_bind->size = tile->u.buffer.length; + vk_bind->memory = vk_memory; + vk_bind->memoryOffset = vk_offset; + vk_bind->flags = 0; + } + + tile->vk_memory = vk_memory; + tile->vk_offset = vk_offset; + } + + /* Ensure that we use a queue that supports sparse binding */ + queue = command_queue->vkd3d_queue; + + if (!(queue->vk_queue_flags & VK_QUEUE_SPARSE_BINDING_BIT)) + queue = command_queue->device->queues[VKD3D_QUEUE_FAMILY_SPARSE_BINDING]; + + if (!(vk_queue = vkd3d_queue_acquire(queue))) + { + ERR("Failed to acquire queue %p.\n", queue); + goto cleanup; + } + + if ((vr = VK_CALL(vkQueueBindSparse(vk_queue, 1, &bind_sparse_info, VK_NULL_HANDLE))) < 0) + ERR("Failed to perform sparse binding, vr %d.\n", vr); + + /* TODO synchronize properly with timeline semaphores */ + if ((vr = VK_CALL(vkQueueWaitIdle(vk_queue))) < 0) + ERR("Failed to synchronize with queue, vr %d.\n", vr); + + vkd3d_queue_release(queue); + +cleanup: + vkd3d_free(memory_binds); + vkd3d_free(image_binds); +} + void d3d12_command_queue_submit_stop(struct d3d12_command_queue *queue) { struct d3d12_command_queue_submission sub; @@ -6987,6 +7160,13 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata) vkd3d_free(submission.u.execute.outstanding_submissions_count); break; + case VKD3D_SUBMISSION_BIND_SPARSE: + d3d12_command_queue_bind_sparse(queue, submission.u.bind_sparse.mode, + submission.u.bind_sparse.dst_resource, submission.u.bind_sparse.src_resource, + submission.u.bind_sparse.bind_count, submission.u.bind_sparse.bind_infos); + vkd3d_free(submission.u.bind_sparse.bind_infos); + break; + case VKD3D_SUBMISSION_DRAIN: { pthread_mutex_lock(&queue->queue_lock); diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 28a903a5..1c06a8c2 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -1254,10 +1254,25 @@ enum vkd3d_submission_type VKD3D_SUBMISSION_WAIT, VKD3D_SUBMISSION_SIGNAL, VKD3D_SUBMISSION_EXECUTE, + VKD3D_SUBMISSION_BIND_SPARSE, VKD3D_SUBMISSION_STOP, VKD3D_SUBMISSION_DRAIN }; +enum vkd3d_sparse_memory_bind_mode +{ + VKD3D_SPARSE_MEMORY_BIND_MODE_UPDATE, + VKD3D_SPARSE_MEMORY_BIND_MODE_COPY, +}; + +struct vkd3d_sparse_memory_bind +{ + uint32_t dst_tile; + uint32_t src_tile; + VkDeviceMemory vk_memory; + VkDeviceSize vk_offset; +}; + struct d3d12_command_queue_submission_wait { struct d3d12_fence *fence; @@ -1277,6 +1292,15 @@ struct d3d12_command_queue_submission_execute UINT count; }; +struct d3d12_command_queue_submission_bind_sparse +{ + enum vkd3d_sparse_memory_bind_mode mode; + uint32_t bind_count; + struct vkd3d_sparse_memory_bind *bind_infos; + struct d3d12_resource *dst_resource; + struct d3d12_resource *src_resource; +}; + struct d3d12_command_queue_submission { enum vkd3d_submission_type type; @@ -1285,6 +1309,7 @@ struct d3d12_command_queue_submission struct d3d12_command_queue_submission_wait wait; struct d3d12_command_queue_submission_signal signal; struct d3d12_command_queue_submission_execute execute; + struct d3d12_command_queue_submission_bind_sparse bind_sparse; } u; };