From b000952e4f543df794fe494534e5ae5224a015b1 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 24 Aug 2017 20:33:49 +0200 Subject: [PATCH] libs/vkd3d: Implement indirect draws. --- libs/vkd3d/command.c | 68 +++++++++++++++++++++++++++++++++++--- libs/vkd3d/device.c | 2 +- libs/vkd3d/vkd3d_private.h | 5 ++- tests/d3d12.c | 51 ++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 7 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 87cf5bd5..c56c9598 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -3282,14 +3282,52 @@ static void STDMETHODCALLTYPE d3d12_command_list_EndEvent(ID3D12GraphicsCommandL } static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(ID3D12GraphicsCommandList *iface, - ID3D12CommandSignature *command_signature, - UINT max_command_count, ID3D12Resource *arg_buffer, + ID3D12CommandSignature *command_signature, UINT max_command_count, ID3D12Resource *arg_buffer, UINT64 arg_buffer_offset, ID3D12Resource *count_buffer, UINT64 count_buffer_offset) { - FIXME("iface %p, command_signature %p, max_command_count %u, arg_buffer %p, " - "arg_buffer_offset %#"PRIx64", count_buffer %p, count_buffer_offset %#"PRIx64" stub!\n", + struct d3d12_command_signature *sig_impl = unsafe_impl_from_ID3D12CommandSignature(command_signature); + struct d3d12_resource *arg_impl = unsafe_impl_from_ID3D12Resource(arg_buffer); + struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList(iface); + const struct vkd3d_vk_device_procs *vk_procs = &list->device->vk_procs; + const D3D12_COMMAND_SIGNATURE_DESC *signature_desc; + unsigned int i; + + TRACE("iface %p, command_signature %p, max_command_count %u, arg_buffer %p, " + "arg_buffer_offset %#"PRIx64", count_buffer %p, count_buffer_offset %#"PRIx64".\n", iface, command_signature, max_command_count, arg_buffer, arg_buffer_offset, count_buffer, count_buffer_offset); + + if (count_buffer) + { + FIXME("Count buffers not implemented.\n"); + return; + } + + signature_desc = &sig_impl->desc; + for (i = 0; i < signature_desc->NumArgumentDescs; ++i) + { + const D3D12_INDIRECT_ARGUMENT_DESC *arg_desc = &signature_desc->pArgumentDescs[i]; + + switch (arg_desc->Type) + { + case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: + if (!d3d12_command_list_begin_render_pass(list, vk_procs)) + { + WARN("Failed to begin render pass, ignoring draw.\n"); + break; + } + + VK_CALL(vkCmdDrawIndirect(list->vk_command_buffer, arg_impl->u.vk_buffer, + arg_buffer_offset, max_command_count, signature_desc->ByteStride)); + + VK_CALL(vkCmdEndRenderPass(list->vk_command_buffer)); + break; + + default: + FIXME("Ignoring unhandled argument type %#x.\n", arg_desc->Type); + break; + } + } } static const struct ID3D12GraphicsCommandListVtbl d3d12_command_list_vtbl = @@ -3888,6 +3926,7 @@ static ULONG STDMETHODCALLTYPE d3d12_command_signature_Release(ID3D12CommandSign { struct d3d12_device *device = signature->device; + vkd3d_free((void *)signature->desc.pArgumentDescs); vkd3d_free(signature); ID3D12Device_Release(&device->ID3D12Device_iface); @@ -3952,7 +3991,16 @@ static const struct ID3D12CommandSignatureVtbl d3d12_command_signature_vtbl = d3d12_command_signature_GetDevice, }; -HRESULT d3d12_command_signature_create(struct d3d12_device *device, struct d3d12_command_signature **signature) +struct d3d12_command_signature *unsafe_impl_from_ID3D12CommandSignature(ID3D12CommandSignature *iface) +{ + if (!iface) + return NULL; + assert(iface->lpVtbl == &d3d12_command_signature_vtbl); + return CONTAINING_RECORD(iface, struct d3d12_command_signature, ID3D12CommandSignature_iface); +} + +HRESULT d3d12_command_signature_create(struct d3d12_device *device, const D3D12_COMMAND_SIGNATURE_DESC *desc, + struct d3d12_command_signature **signature) { struct d3d12_command_signature *object; @@ -3961,6 +4009,16 @@ HRESULT d3d12_command_signature_create(struct d3d12_device *device, struct d3d12 object->ID3D12CommandSignature_iface.lpVtbl = &d3d12_command_signature_vtbl; object->refcount = 1; + + object->desc = *desc; + if (!(object->desc.pArgumentDescs = vkd3d_calloc(desc->NumArgumentDescs, sizeof(*desc->pArgumentDescs)))) + { + vkd3d_free(object); + return E_OUTOFMEMORY; + } + memcpy((void *)object->desc.pArgumentDescs, desc->pArgumentDescs, + desc->NumArgumentDescs * sizeof(*desc->pArgumentDescs)); + object->device = device; ID3D12Device_AddRef(&device->ID3D12Device_iface); diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index f3e82fd8..10aecaf0 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -1444,7 +1444,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandSignature(ID3D12Devic TRACE("iface %p, desc %p, root_signature %p, iid %s, command_signature %p.\n", iface, desc, root_signature, debugstr_guid(iid), command_signature); - if (FAILED(hr = d3d12_command_signature_create(device, &object))) + if (FAILED(hr = d3d12_command_signature_create(device, desc, &object))) return hr; return return_interface((IUnknown *)&object->ID3D12CommandSignature_iface, diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 2d95debb..f36ad9d3 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -494,11 +494,14 @@ struct d3d12_command_signature ID3D12CommandSignature ID3D12CommandSignature_iface; LONG refcount; + D3D12_COMMAND_SIGNATURE_DESC desc; + struct d3d12_device *device; }; -HRESULT d3d12_command_signature_create(struct d3d12_device *device, +HRESULT d3d12_command_signature_create(struct d3d12_device *device, const D3D12_COMMAND_SIGNATURE_DESC *desc, struct d3d12_command_signature **signature) DECLSPEC_HIDDEN; +struct d3d12_command_signature *unsafe_impl_from_ID3D12CommandSignature(ID3D12CommandSignature *iface) DECLSPEC_HIDDEN; struct vkd3d_vulkan_info { diff --git a/tests/d3d12.c b/tests/d3d12.c index 419a63ca..d151ecca 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -11488,6 +11488,56 @@ static void test_query_pipeline_statistics(void) destroy_test_context(&context); } +static void test_execute_indirect(void) +{ + D3D12_COMMAND_SIGNATURE_DESC signature_desc; + D3D12_INDIRECT_ARGUMENT_DESC argument_desc; + ID3D12CommandSignature *command_signature; + ID3D12GraphicsCommandList *command_list; + ID3D12Resource *argument_buffer; + struct test_context context; + ID3D12CommandQueue *queue; + HRESULT hr; + + static const D3D12_DRAW_ARGUMENTS argument_data = {3, 1, 0, 0}; + static const float white[] = {1.0f, 1.0f, 1.0f, 1.0f}; + + if (!init_test_context(&context, NULL)) + return; + command_list = context.list; + queue = context.queue; + + argument_buffer = create_upload_buffer(context.device, sizeof(argument_data), &argument_data); + + argument_desc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; + + signature_desc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); + signature_desc.NumArgumentDescs = 1; + signature_desc.pArgumentDescs = &argument_desc; + signature_desc.NodeMask = 0; + hr = ID3D12Device_CreateCommandSignature(context.device, &signature_desc, + NULL, &IID_ID3D12CommandSignature, (void **)&command_signature); + ok(SUCCEEDED(hr), "Failed to create command signature, hr %#x.\n", hr); + + ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, context.rtv, white, 0, NULL); + + ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &context.rtv, FALSE, NULL); + ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, context.root_signature); + ID3D12GraphicsCommandList_SetPipelineState(command_list, context.pipeline_state); + ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &context.viewport); + ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &context.scissor_rect); + ID3D12GraphicsCommandList_ExecuteIndirect(command_list, command_signature, 1, argument_buffer, 0, NULL, 0); + + transition_resource_state(command_list, context.render_target, + D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); + check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0); + + ID3D12CommandSignature_Release(command_signature); + ID3D12Resource_Release(argument_buffer); + destroy_test_context(&context); +} + START_TEST(d3d12) { bool enable_debug_layer = false; @@ -11561,4 +11611,5 @@ START_TEST(d3d12) run_test(test_create_query_heap); run_test(test_query_timestamp); run_test(test_query_pipeline_statistics); + run_test(test_execute_indirect); }