vkd3d: Avoid vkResetCommandPool if there are pending command buffers.

Works around an app-bug in SotTR, where the command pool is reset before
the command buffer completes.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2020-04-17 15:10:07 +02:00
parent 334b1cab8d
commit 09af24e69b
2 changed files with 42 additions and 1 deletions

View File

@ -1038,6 +1038,7 @@ static HRESULT d3d12_command_allocator_allocate_command_buffer(struct d3d12_comm
} }
allocator->current_command_list = list; allocator->current_command_list = list;
list->outstanding_submissions_count = &allocator->outstanding_submissions_count;
return S_OK; return S_OK;
} }
@ -1500,6 +1501,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_Reset(ID3D12CommandAllo
const struct vkd3d_vk_device_procs *vk_procs; const struct vkd3d_vk_device_procs *vk_procs;
struct d3d12_command_list *list; struct d3d12_command_list *list;
struct d3d12_device *device; struct d3d12_device *device;
LONG pending;
VkResult vr; VkResult vr;
TRACE("iface %p.\n", iface); TRACE("iface %p.\n", iface);
@ -1515,6 +1517,23 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_allocator_Reset(ID3D12CommandAllo
TRACE("Resetting command list %p.\n", list); TRACE("Resetting command list %p.\n", list);
} }
if ((pending = atomic_add_fetch(&allocator->outstanding_submissions_count, 0)) != 0)
{
/* HACK: There are currently command lists waiting to be submitted to the queue in the submission threads.
* Buggy application, but work around this by not resetting the command pool this time.
* To be perfectly safe, we can only reset after the fence timeline is signalled,
* however, this is enough to workaround SotTR which resets the command list right
* after calling ID3D12CommandQueue::ExecuteCommandLists().
* Only happens once or twice on bootup and doesn't cause memory leaks over time
* since the command pool is eventually reset.
* Game does not seem to care if E_FAIL is returned, which is the correct thing to do here.
*
* TODO: Guard this with actual timeline semaphores from vkQueueSubmit(). */
ERR("There are still %u pending command lists awaiting execution from command allocator iface %p!\n",
(unsigned int)pending, iface);
return E_FAIL;
}
device = allocator->device; device = allocator->device;
vk_procs = &device->vk_procs; vk_procs = &device->vk_procs;
@ -1595,7 +1614,7 @@ static HRESULT d3d12_command_allocator_init(struct d3d12_command_allocator *allo
allocator->ID3D12CommandAllocator_iface.lpVtbl = &d3d12_command_allocator_vtbl; allocator->ID3D12CommandAllocator_iface.lpVtbl = &d3d12_command_allocator_vtbl;
allocator->refcount = 1; allocator->refcount = 1;
allocator->outstanding_submissions_count = 0;
allocator->type = type; allocator->type = type;
allocator->vk_queue_flags = queue->vk_queue_flags; allocator->vk_queue_flags = queue->vk_queue_flags;
@ -6081,6 +6100,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
struct d3d12_command_queue_submission sub; struct d3d12_command_queue_submission sub;
struct d3d12_command_list *cmd_list; struct d3d12_command_list *cmd_list;
VkCommandBuffer *buffers; VkCommandBuffer *buffers;
LONG **outstanding;
unsigned int i, j; unsigned int i, j;
TRACE("iface %p, command_list_count %u, command_lists %p.\n", TRACE("iface %p, command_list_count %u, command_lists %p.\n",
@ -6092,6 +6112,12 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
return; return;
} }
if (!(outstanding = vkd3d_calloc(command_list_count, sizeof(*outstanding))))
{
ERR("Failed to allocate outstanding submissions count.\n");
return;
}
for (i = 0; i < command_list_count; ++i) for (i = 0; i < command_list_count; ++i)
{ {
cmd_list = unsafe_impl_from_ID3D12CommandList(command_lists[i]); cmd_list = unsafe_impl_from_ID3D12CommandList(command_lists[i]);
@ -6104,6 +6130,9 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
return; return;
} }
outstanding[i] = cmd_list->outstanding_submissions_count;
InterlockedIncrement(outstanding[i]);
for (j = 0; j < cmd_list->descriptor_updates_count; j++) for (j = 0; j < cmd_list->descriptor_updates_count; j++)
d3d12_deferred_descriptor_set_update_resolve(cmd_list, &cmd_list->descriptor_updates[j]); d3d12_deferred_descriptor_set_update_resolve(cmd_list, &cmd_list->descriptor_updates[j]);
buffers[i] = cmd_list->vk_command_buffer; buffers[i] = cmd_list->vk_command_buffer;
@ -6112,6 +6141,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
sub.type = VKD3D_SUBMISSION_EXECUTE; sub.type = VKD3D_SUBMISSION_EXECUTE;
sub.u.execute.cmd = buffers; sub.u.execute.cmd = buffers;
sub.u.execute.count = command_list_count; sub.u.execute.count = command_list_count;
sub.u.execute.outstanding_submissions_count = outstanding;
d3d12_command_queue_add_submission(command_queue, &sub); d3d12_command_queue_add_submission(command_queue, &sub);
} }
@ -6470,6 +6500,8 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata)
{ {
struct d3d12_command_queue_submission submission; struct d3d12_command_queue_submission submission;
struct d3d12_command_queue *queue = userdata; struct d3d12_command_queue *queue = userdata;
unsigned int i;
vkd3d_set_thread_name("vkd3d_queue"); vkd3d_set_thread_name("vkd3d_queue");
for (;;) for (;;)
@ -6499,6 +6531,10 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata)
case VKD3D_SUBMISSION_EXECUTE: case VKD3D_SUBMISSION_EXECUTE:
d3d12_command_queue_execute(queue, submission.u.execute.cmd, submission.u.execute.count); d3d12_command_queue_execute(queue, submission.u.execute.cmd, submission.u.execute.count);
vkd3d_free(submission.u.execute.cmd); vkd3d_free(submission.u.execute.cmd);
/* TODO: The correct place to do this would be in a fence handler, but this is good enough for now. */
for (i = 0; i < submission.u.execute.count; i++)
InterlockedDecrement(submission.u.execute.outstanding_submissions_count[i]);
vkd3d_free(submission.u.execute.outstanding_submissions_count);
break; break;
case VKD3D_SUBMISSION_DRAIN: case VKD3D_SUBMISSION_DRAIN:

View File

@ -1032,6 +1032,8 @@ struct d3d12_command_allocator
size_t command_buffers_size; size_t command_buffers_size;
size_t command_buffer_count; size_t command_buffer_count;
LONG outstanding_submissions_count;
struct d3d12_command_list *current_command_list; struct d3d12_command_list *current_command_list;
struct d3d12_device *device; struct d3d12_device *device;
@ -1164,6 +1166,8 @@ struct d3d12_command_list
size_t descriptor_updates_size; size_t descriptor_updates_size;
size_t descriptor_updates_count; size_t descriptor_updates_count;
LONG *outstanding_submissions_count;
struct vkd3d_private_store private_store; struct vkd3d_private_store private_store;
}; };
@ -1214,6 +1218,7 @@ struct d3d12_command_queue_submission_signal
struct d3d12_command_queue_submission_execute struct d3d12_command_queue_submission_execute
{ {
VkCommandBuffer *cmd; VkCommandBuffer *cmd;
LONG **outstanding_submissions_count;
UINT count; UINT count;
}; };