vkd3d: Implement sparse binding.

Signed-off-by: Philip Rebohle <philip.rebohle@tu-dortmund.de>
This commit is contained in:
Philip Rebohle 2020-05-05 19:44:16 +02:00 committed by Hans-Kristian Arntzen
parent 7836c06204
commit e3eb3498c2
2 changed files with 205 additions and 0 deletions

View File

@ -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);

View File

@ -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;
};