305 lines
14 KiB
Diff
305 lines
14 KiB
Diff
diff --git a/include/vkd3d_device_vkd3d_ext.idl b/include/vkd3d_device_vkd3d_ext.idl
|
|
index 680f2c96..1fddc28e 100644
|
|
--- a/include/vkd3d_device_vkd3d_ext.idl
|
|
+++ b/include/vkd3d_device_vkd3d_ext.idl
|
|
@@ -104,6 +104,21 @@ interface ID3D12DXVKInteropDevice3 : ID3D12DXVKInteropDevice2
|
|
UINT32 *vk_memory_type);
|
|
}
|
|
|
|
+[
|
|
+ uuid(5a7c8b3e-2f61-4d0e-9c1a-7e3b52d4a901),
|
|
+ object,
|
|
+ local,
|
|
+ pointer_default(unique)
|
|
+]
|
|
+interface ID3D12DXVKInteropDeviceD4R : ID3D12DXVKInteropDevice3
|
|
+{
|
|
+ /* d4r: ends the command list's current Vulkan command buffer. Everything
|
|
+ * recorded afterwards is submitted separately and waits (as a queue
|
|
+ * submission wait, not a GPU-side wait) until the timeline semaphore
|
|
+ * vk_semaphore reaches value. */
|
|
+ HRESULT SplitCommandListForExternalWait(ID3D12CommandList *list, UINT64 vk_semaphore, UINT64 value);
|
|
+}
|
|
+
|
|
[
|
|
uuid(f3112584-41f9-348d-a59b-00b7e1d285d6),
|
|
object,
|
|
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
|
|
index 611e373b..23af78a5 100644
|
|
--- a/libs/vkd3d/command.c
|
|
+++ b/libs/vkd3d/command.c
|
|
@@ -2557,6 +2557,38 @@ static void d3d12_command_list_consider_new_sequence(struct d3d12_command_list *
|
|
}
|
|
}
|
|
|
|
+HRESULT d3d12_command_list_split_for_external_wait(struct d3d12_command_list *list,
|
|
+ VkSemaphore semaphore, uint64_t value)
|
|
+{
|
|
+ struct d3d12_command_list_iteration *iteration;
|
|
+ unsigned int count;
|
|
+
|
|
+ if (!list->is_recording)
|
|
+ return E_INVALIDARG;
|
|
+ if (!d3d12_command_list_allows_new_sequence(list))
|
|
+ {
|
|
+ WARN("Cannot split command list for external wait with a running query.\n");
|
|
+ return E_FAIL;
|
|
+ }
|
|
+
|
|
+ /* Flush everything recorded so far into the current command buffer. */
|
|
+ d3d12_command_list_decay_tracked_state(list);
|
|
+ d3d12_command_list_invalidate_all_state(list);
|
|
+
|
|
+ count = list->cmd.iteration_count;
|
|
+ d3d12_command_list_begin_new_sequence(list, false);
|
|
+ if (list->cmd.iteration_count == count)
|
|
+ {
|
|
+ WARN("Out of command list sequences for external wait.\n");
|
|
+ return E_FAIL;
|
|
+ }
|
|
+
|
|
+ iteration = &list->cmd.iterations[list->cmd.iteration_count - 1];
|
|
+ iteration->external_wait_semaphore = semaphore;
|
|
+ iteration->external_wait_value = value;
|
|
+ return S_OK;
|
|
+}
|
|
+
|
|
static void d3d12_command_list_copy_queue_fallback(struct d3d12_command_list *list)
|
|
{
|
|
if (!list->cmd.iterations[list->cmd.iteration_count - 1].fallback)
|
|
@@ -22769,6 +22801,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
|
|
struct vkd3d_initial_transition *transitions;
|
|
size_t num_transitions, num_command_buffers;
|
|
VkCommandBufferSubmitInfo *buffers, *buffer;
|
|
+ VkSemaphoreSubmitInfo *external_waits = NULL;
|
|
struct d3d12_command_allocator **allocators;
|
|
struct d3d12_command_queue_submission sub;
|
|
unsigned int indirect_barrier_hoist_index;
|
|
@@ -22954,6 +22987,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
|
|
vkd3d_free(allocators);
|
|
vkd3d_free(buffers);
|
|
vkd3d_free(cmd_cost);
|
|
+ vkd3d_free(external_waits);
|
|
#ifdef VKD3D_ENABLE_BREADCRUMBS
|
|
vkd3d_free(breadcrumb_indices);
|
|
#endif
|
|
@@ -23036,6 +23070,21 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
|
|
buffer->commandBuffer = cmd_list->cmd.iterations[iter].vk_command_buffer;
|
|
/* Pilfer this for purposes of signalling aux data. No need to allocate more stuff just to signal this. */
|
|
buffer->deviceMask = cmd_list->cmd.iterations[iter].fallback ? VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_FALLBACK_QUEUE : 0;
|
|
+
|
|
+ if (cmd_list->cmd.iterations[iter].external_wait_semaphore)
|
|
+ {
|
|
+ if (!external_waits)
|
|
+ external_waits = vkd3d_calloc(num_command_buffers, sizeof(*external_waits));
|
|
+ if (external_waits)
|
|
+ {
|
|
+ VkSemaphoreSubmitInfo *wait = &external_waits[cmd_submit_count - 1];
|
|
+ wait->sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO;
|
|
+ wait->semaphore = cmd_list->cmd.iterations[iter].external_wait_semaphore;
|
|
+ wait->value = cmd_list->cmd.iterations[iter].external_wait_value;
|
|
+ wait->stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
|
|
+ buffer->deviceMask |= VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_EXTERNAL_WAIT;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
need_suspend_fixup = cmd_list->cmd.suspend_resume.suspend.vk_fixup_cmd_buffer && (i + 1 == command_list_count ||
|
|
@@ -23155,6 +23204,7 @@ static void STDMETHODCALLTYPE d3d12_command_queue_ExecuteCommandLists(ID3D12Comm
|
|
sub.type = VKD3D_SUBMISSION_EXECUTE;
|
|
sub.execute.cmd = buffers;
|
|
sub.execute.cmd_cost = cmd_cost;
|
|
+ sub.execute.external_waits = external_waits;
|
|
sub.execute.cmd_count = cmd_submit_count;
|
|
sub.execute.command_allocators = allocators;
|
|
sub.execute.num_command_allocators = command_list_count;
|
|
@@ -24377,6 +24427,8 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu
|
|
VkSemaphoreSubmitInfo *binary_semaphore_info;
|
|
bool stagger_submissions, is_first, is_last;
|
|
VkSemaphoreSubmitInfo wait_semaphore_info;
|
|
+ VkSemaphoreSubmitInfo combined_wait_infos[2];
|
|
+ bool external_wait;
|
|
uint32_t cmd_index, cmd_count, total_cost;
|
|
struct vkd3d_fence_wait_info fence_info;
|
|
VkSubmitInfo2 submit_desc[2], *submit;
|
|
@@ -24516,7 +24568,15 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu
|
|
total_cost = 0;
|
|
|
|
for (i = cmd_index + cmd_count; i < exec->cmd_count && total_cost < VKD3D_COMMAND_COST_MERGE_THRESHOLD; i++)
|
|
+ {
|
|
+ /* d4r: never merge across an external wait. */
|
|
+ if (exec->cmd[i].deviceMask & VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_EXTERNAL_WAIT)
|
|
+ {
|
|
+ total_cost = VKD3D_COMMAND_COST_MERGE_THRESHOLD;
|
|
+ break;
|
|
+ }
|
|
total_cost += exec->cmd_cost[i];
|
|
+ }
|
|
|
|
if (total_cost < VKD3D_COMMAND_COST_MERGE_THRESHOLD)
|
|
cmd_count = exec->cmd_count - cmd_index;
|
|
@@ -24525,8 +24585,14 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu
|
|
{
|
|
/* Submit everything at once, until we hit a fallback queue submission. Pick that up next iteration. */
|
|
for (cmd_count = 0; cmd_index + cmd_count < exec->cmd_count; cmd_count++)
|
|
+ {
|
|
if (exec->cmd[cmd_index + cmd_count].deviceMask & VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_FALLBACK_QUEUE)
|
|
break;
|
|
+ /* d4r: an external wait starts a new submit. */
|
|
+ if (cmd_count && (exec->cmd[cmd_index + cmd_count].deviceMask &
|
|
+ VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_EXTERNAL_WAIT))
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
submit = &submit_desc[num_submits++];
|
|
@@ -24536,6 +24602,9 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu
|
|
submit->signalSemaphoreInfoCount = 1;
|
|
submit->pSignalSemaphoreInfos = signal_semaphore_infos;
|
|
|
|
+ external_wait = cmd_count && exec->external_waits &&
|
|
+ (exec->cmd[cmd_index].deviceMask & VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_EXTERNAL_WAIT);
|
|
+
|
|
/* Clear out any shenanigans we added due to fallback submit. */
|
|
for (i = 0; i < cmd_count; i++)
|
|
exec->cmd[cmd_index + i].deviceMask = 0;
|
|
@@ -24555,6 +24624,23 @@ static void d3d12_command_queue_execute(struct d3d12_command_queue *command_queu
|
|
submit->pWaitSemaphoreInfos = &wait_semaphore_info;
|
|
}
|
|
|
|
+ if (external_wait)
|
|
+ {
|
|
+ /* d4r: a queue-level wait-before-signal; the host signals the value later. */
|
|
+ if (submit->waitSemaphoreInfoCount)
|
|
+ {
|
|
+ combined_wait_infos[0] = submit->pWaitSemaphoreInfos[0];
|
|
+ combined_wait_infos[1] = exec->external_waits[cmd_index];
|
|
+ submit->waitSemaphoreInfoCount = 2;
|
|
+ submit->pWaitSemaphoreInfos = combined_wait_infos;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ submit->waitSemaphoreInfoCount = 1;
|
|
+ submit->pWaitSemaphoreInfos = &exec->external_waits[cmd_index];
|
|
+ }
|
|
+ }
|
|
+
|
|
cmd_index += cmd_count;
|
|
is_last = cmd_index == exec->cmd_count;
|
|
|
|
@@ -25347,6 +25433,7 @@ static void *d3d12_command_queue_submission_worker_main(void *userdata)
|
|
* On error, the counters are freed early, so there is no risk of leak. */
|
|
vkd3d_free(submission.execute.cmd);
|
|
vkd3d_free(submission.execute.cmd_cost);
|
|
+ vkd3d_free(submission.execute.external_waits);
|
|
vkd3d_free(submission.execute.transitions);
|
|
#ifdef VKD3D_ENABLE_BREADCRUMBS
|
|
for (i = 0; i < submission.execute.breadcrumb_indices_count; i++)
|
|
diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c
|
|
index f6db6954..06955941 100644
|
|
--- a/libs/vkd3d/device.c
|
|
+++ b/libs/vkd3d/device.c
|
|
@@ -4657,7 +4657,8 @@ HRESULT STDMETHODCALLTYPE d3d12_device_QueryInterface(d3d12_device_iface *iface,
|
|
if (IsEqualGUID(riid, &IID_ID3D12DXVKInteropDevice)
|
|
|| IsEqualGUID(riid, &IID_ID3D12DXVKInteropDevice1)
|
|
|| IsEqualGUID(riid, &IID_ID3D12DXVKInteropDevice2)
|
|
- || IsEqualGUID(riid, &IID_ID3D12DXVKInteropDevice3))
|
|
+ || IsEqualGUID(riid, &IID_ID3D12DXVKInteropDevice3)
|
|
+ || IsEqualGUID(riid, &IID_ID3D12DXVKInteropDeviceD4R))
|
|
{
|
|
d3d12_dxvk_interop_device_AddRef(&device->ID3D12DXVKInteropDevice_iface);
|
|
*object = &device->ID3D12DXVKInteropDevice_iface;
|
|
@@ -11379,7 +11380,7 @@ static void d3d12_device_replace_vtable(struct d3d12_device *device)
|
|
}
|
|
|
|
extern CONST_VTBL struct ID3D12DeviceExt5Vtbl d3d12_device_vkd3d_ext_vtbl;
|
|
-extern CONST_VTBL struct ID3D12DXVKInteropDevice3Vtbl d3d12_dxvk_interop_device_vtbl;
|
|
+extern CONST_VTBL struct ID3D12DXVKInteropDeviceD4RVtbl d3d12_dxvk_interop_device_vtbl;
|
|
extern CONST_VTBL struct ID3DLowLatencyDeviceVtbl d3d_low_latency_device_vtbl;
|
|
extern CONST_VTBL struct IAmdExtAntiLagApiVtbl d3d_amd_ext_anti_lag_vtbl;
|
|
|
|
diff --git a/libs/vkd3d/device_vkd3d_ext.c b/libs/vkd3d/device_vkd3d_ext.c
|
|
index 94818b9a..bd5dd7a5 100644
|
|
--- a/libs/vkd3d/device_vkd3d_ext.c
|
|
+++ b/libs/vkd3d/device_vkd3d_ext.c
|
|
@@ -1145,7 +1145,19 @@ static HRESULT STDMETHODCALLTYPE d3d12_dxvk_interop_device_GetVulkanHeapInfo(d3d
|
|
return S_OK;
|
|
}
|
|
|
|
-CONST_VTBL struct ID3D12DXVKInteropDevice3Vtbl d3d12_dxvk_interop_device_vtbl =
|
|
+static HRESULT STDMETHODCALLTYPE d3d12_dxvk_interop_device_SplitCommandListForExternalWait(
|
|
+ d3d12_dxvk_interop_device_iface *iface, ID3D12CommandList *list, UINT64 vk_semaphore, UINT64 value)
|
|
+{
|
|
+ struct d3d12_command_list *cmd_list = d3d12_command_list_from_iface(list);
|
|
+
|
|
+ TRACE("iface %p, list %p, vk_semaphore 0x%"PRIx64", value %"PRIu64".\n", iface, list, vk_semaphore, value);
|
|
+
|
|
+ if (!cmd_list || !vk_semaphore)
|
|
+ return E_INVALIDARG;
|
|
+ return d3d12_command_list_split_for_external_wait(cmd_list, (VkSemaphore)vk_semaphore, value);
|
|
+}
|
|
+
|
|
+CONST_VTBL struct ID3D12DXVKInteropDeviceD4RVtbl d3d12_dxvk_interop_device_vtbl =
|
|
{
|
|
/* IUnknown methods */
|
|
d3d12_dxvk_interop_device_QueryInterface,
|
|
@@ -1177,6 +1189,9 @@ CONST_VTBL struct ID3D12DXVKInteropDevice3Vtbl d3d12_dxvk_interop_device_vtbl =
|
|
|
|
/* ID3D12DXVKInteropDevice3 methods */
|
|
d3d12_dxvk_interop_device_GetVulkanHeapInfo,
|
|
+
|
|
+ /* ID3D12DXVKInteropDeviceD4R methods */
|
|
+ d3d12_dxvk_interop_device_SplitCommandListForExternalWait,
|
|
};
|
|
|
|
static inline struct d3d12_device *d3d12_device_from_ID3DLowLatencyDevice(d3d_low_latency_device_iface *iface)
|
|
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
|
|
index a2a78000..64338585 100644
|
|
--- a/libs/vkd3d/vkd3d_private.h
|
|
+++ b/libs/vkd3d/vkd3d_private.h
|
|
@@ -3207,6 +3207,9 @@ struct d3d12_command_list_iteration
|
|
uint32_t estimated_cost;
|
|
bool fallback; /* Only applies to vk_command_buffer. */
|
|
struct d3d12_command_list_iteration_indirect_meta indirect_meta;
|
|
+ /* d4r: vk_command_buffer is submitted separately, after this timeline value is reached. */
|
|
+ VkSemaphore external_wait_semaphore;
|
|
+ uint64_t external_wait_value;
|
|
};
|
|
|
|
enum
|
|
@@ -3216,9 +3219,12 @@ enum
|
|
* without having to add more allocations. */
|
|
VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_DEFAULT = 0,
|
|
VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_FALLBACK_QUEUE = 1u << 0,
|
|
+ /* d4r: starts a new submit that waits for submission_execute::external_waits[index]. */
|
|
+ VKD3D_COMMAND_BUFFER_SUBMIT_INFO_DEVICE_MASK_EXTERNAL_WAIT = 1u << 1,
|
|
};
|
|
|
|
-#define VKD3D_MAX_COMMAND_LIST_SEQUENCES 2
|
|
+/* d4r: 4 so an external-wait split fits next to DGC and fallback splits. */
|
|
+#define VKD3D_MAX_COMMAND_LIST_SEQUENCES 4
|
|
|
|
#define VKD3D_COMMAND_COST_LOW (1u)
|
|
#define VKD3D_COMMAND_COST_HIGH (16u)
|
|
@@ -3737,6 +3743,8 @@ struct d3d12_command_queue_submission_execute
|
|
{
|
|
VkCommandBufferSubmitInfo *cmd;
|
|
uint32_t *cmd_cost;
|
|
+ /* d4r: indexed like cmd, only allocated when a command buffer waits externally. */
|
|
+ VkSemaphoreSubmitInfo *external_waits;
|
|
struct d3d12_command_allocator **command_allocators;
|
|
UINT cmd_count;
|
|
UINT num_command_allocators;
|
|
@@ -5463,7 +5471,10 @@ struct vkd3d_timestamp_profiler;
|
|
typedef ID3D12DeviceExt5 d3d12_device_vkd3d_ext_iface;
|
|
|
|
/* ID3D12DXVKInteropDevice */
|
|
-typedef ID3D12DXVKInteropDevice3 d3d12_dxvk_interop_device_iface;
|
|
+HRESULT d3d12_command_list_split_for_external_wait(struct d3d12_command_list *list,
|
|
+ VkSemaphore semaphore, uint64_t value);
|
|
+
|
|
+typedef ID3D12DXVKInteropDeviceD4R d3d12_dxvk_interop_device_iface;
|
|
|
|
/* ID3DLowLatencyDevice */
|
|
typedef ID3DLowLatencyDevice d3d_low_latency_device_iface;
|