From: Conor McCarthy Subject: [PATCH vkd3d 5/5] vkd3d: Introduce command list type bundle. Message-Id: <20210903145859.2490-5-cmccarthy@codeweavers.com> Date: Sat, 4 Sep 2021 00:58:59 +1000 In-Reply-To: <20210903145859.2490-1-cmccarthy@codeweavers.com> References: <20210903145859.2490-1-cmccarthy@codeweavers.com> Only DrawInstanced() is supported in this patch. Modern compilers use a binary search for switch statements, so the performance impact will be not too great when all valid command list methods are handled. Signed-off-by: Conor McCarthy --- Makefile.am | 1 + libs/vkd3d/bundle.c | 1102 ++++++++++++++++++++++++++++++++++++ libs/vkd3d/command.c | 60 +- libs/vkd3d/device.c | 47 +- libs/vkd3d/vkd3d_private.h | 76 +++ tests/d3d12.c | 9 +- 6 files changed, 1275 insertions(+), 20 deletions(-) create mode 100644 libs/vkd3d/bundle.c diff --git a/Makefile.am b/Makefile.am index f51233c2..9a0b868f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -200,6 +200,7 @@ libvkd3d_la_SOURCES = \ include/vkd3d_d3d12.idl \ include/vkd3d_d3dcommon.idl \ include/vkd3d_unknown.idl \ + libs/vkd3d/bundle.c \ libs/vkd3d/command.c \ libs/vkd3d/device.c \ libs/vkd3d/resource.c \ diff --git a/libs/vkd3d/bundle.c b/libs/vkd3d/bundle.c new file mode 100644 index 00000000..dd3aadf7 --- /dev/null +++ b/libs/vkd3d/bundle.c @@ -0,0 +1,1102 @@ +/* + * Copyright 2021 Conor McCarthy for CodeWeavers. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "vkd3d_private.h" + +static void d3d12_bundle_command_buffer_reset(struct d3d12_bundle_command_buffer *command_buffer) +{ + command_buffer->commands = NULL; + command_buffer->size = 0; + command_buffer->count = 0; +} + +static bool d3d12_bundle_command_buffer_reserve(struct d3d12_bundle_command_buffer *command_buffer, + size_t count, enum vkd3d_command_list_command_id id) +{ + size_t new_count = command_buffer->count + 1 + count; + + if (!vkd3d_array_reserve((void **)&command_buffer->commands, &command_buffer->size, + max(new_count, 32), sizeof(*command_buffer->commands))) + { + ERR("Out of memory. Cannot record bundle command %#x.\n", id); + return false; + } + + command_buffer->commands[command_buffer->count].header.count = count; + command_buffer->commands[command_buffer->count++].header.id = id; + + return true; +} + +static void d3d12_bundle_begin_command_buffer(struct d3d12_bundle *bundle) +{ + bundle->is_recording = true; + bundle->is_valid = true; +} + +static void d3d12_bundle_allocator_destroyed(struct d3d12_bundle *bundle) +{ + TRACE("bundle %p.\n", bundle); + + bundle->allocator = NULL; + d3d12_bundle_command_buffer_reset(&bundle->command_buffer); +} + +/* ID3D12CommandAllocator */ +static inline struct d3d12_bundle_allocator *impl_from_ID3D12CommandAllocator(ID3D12CommandAllocator *iface) +{ + return CONTAINING_RECORD(iface, struct d3d12_bundle_allocator, ID3D12CommandAllocator_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_QueryInterface(ID3D12CommandAllocator *iface, + REFIID riid, void **object) +{ + TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); + + if (IsEqualGUID(riid, &IID_ID3D12CommandAllocator) + || IsEqualGUID(riid, &IID_ID3D12Pageable) + || IsEqualGUID(riid, &IID_ID3D12DeviceChild) + || IsEqualGUID(riid, &IID_ID3D12Object) + || IsEqualGUID(riid, &IID_IUnknown)) + { + ID3D12CommandAllocator_AddRef(iface); + *object = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); + + *object = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d3d12_bundle_allocator_AddRef(ID3D12CommandAllocator *iface) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + ULONG refcount = InterlockedIncrement(&allocator->refcount); + + TRACE("%p increasing refcount to %u.\n", allocator, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d3d12_bundle_allocator_Release(ID3D12CommandAllocator *iface) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + ULONG refcount = InterlockedDecrement(&allocator->refcount); + + TRACE("%p decreasing refcount to %u.\n", allocator, refcount); + + if (!refcount) + { + struct d3d12_device *device = allocator->device; + size_t i; + + vkd3d_private_store_destroy(&allocator->private_store); + + if (allocator->current_bundle) + d3d12_bundle_allocator_destroyed(allocator->current_bundle); + + for (i = 0; i < allocator->arg_buffer_count; ++i) + vkd3d_free(allocator->arg_buffers[i]); + vkd3d_free(allocator->arg_buffers); + + vkd3d_free(allocator); + + d3d12_device_release(device); + } + + return refcount; +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_GetPrivateData(ID3D12CommandAllocator *iface, + REFGUID guid, UINT *data_size, void *data) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + + TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return vkd3d_get_private_data(&allocator->private_store, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_SetPrivateData(ID3D12CommandAllocator *iface, + REFGUID guid, UINT data_size, const void *data) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + + TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return vkd3d_set_private_data(&allocator->private_store, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_SetPrivateDataInterface(ID3D12CommandAllocator *iface, + REFGUID guid, const IUnknown *data) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + + TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data); + + return vkd3d_set_private_data_interface(&allocator->private_store, guid, data); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_SetName(ID3D12CommandAllocator *iface, const WCHAR *name) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + + TRACE("iface %p, name %s.\n", iface, debugstr_w(name, allocator->device->wchar_size)); + + return name ? S_OK : E_INVALIDARG; +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_GetDevice(ID3D12CommandAllocator *iface, REFIID iid, void **device) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + + TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device); + + return d3d12_device_query_interface(allocator->device, iid, device); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_allocator_Reset(ID3D12CommandAllocator *iface) +{ + struct d3d12_bundle_allocator *allocator = impl_from_ID3D12CommandAllocator(iface); + struct d3d12_bundle *bundle; + size_t i; + + TRACE("iface %p.\n", iface); + + if ((bundle = allocator->current_bundle)) + { + if (bundle->is_recording) + { + WARN("A command list using this allocator is in the recording state.\n"); + return E_FAIL; + } + + TRACE("Resetting command list %p.\n", bundle); + } + + for (i = 0; i < allocator->arg_buffer_count; ++i) + vkd3d_free(allocator->arg_buffers[i]); + allocator->arg_buffer_count = 0; + + return S_OK; +} + +static const struct ID3D12CommandAllocatorVtbl d3d12_bundle_allocator_vtbl = +{ + /* IUnknown methods */ + d3d12_bundle_allocator_QueryInterface, + d3d12_bundle_allocator_AddRef, + d3d12_bundle_allocator_Release, + /* ID3D12Object methods */ + d3d12_bundle_allocator_GetPrivateData, + d3d12_bundle_allocator_SetPrivateData, + d3d12_bundle_allocator_SetPrivateDataInterface, + d3d12_bundle_allocator_SetName, + /* ID3D12DeviceChild methods */ + d3d12_bundle_allocator_GetDevice, + /* ID3D12CommandAllocator methods */ + d3d12_bundle_allocator_Reset, +}; + +static struct d3d12_bundle_allocator *checked_impl_from_ID3D12CommandAllocator(ID3D12CommandAllocator *iface) +{ + if (iface->lpVtbl != &d3d12_bundle_allocator_vtbl) + return NULL; + return impl_from_ID3D12CommandAllocator(iface); +} + +HRESULT d3d12_bundle_allocator_create(struct d3d12_device *device, struct d3d12_bundle_allocator **allocator) +{ + struct d3d12_bundle_allocator *object; + HRESULT hr; + + if (!(object = vkd3d_calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->ID3D12CommandAllocator_iface.lpVtbl = &d3d12_bundle_allocator_vtbl; + object->refcount = 1; + + if (FAILED(hr = vkd3d_private_store_init(&object->private_store))) + { + vkd3d_free(object); + return hr; + } + + d3d12_device_add_ref(object->device = device); + + TRACE("Created command allocator %p.\n", object); + + *allocator = object; + + return S_OK; +} + +static HRESULT d3d12_bundle_allocator_init_command_buffer(struct d3d12_bundle_allocator *allocator, + struct d3d12_bundle *bundle) +{ + TRACE("allocator %p, bundle %p.\n", allocator, bundle); + + if (allocator->current_bundle) + { + WARN("Command allocator is already in use.\n"); + return E_INVALIDARG; + } + + d3d12_bundle_command_buffer_reset(&bundle->command_buffer); + + d3d12_bundle_begin_command_buffer(bundle); + + allocator->current_bundle = bundle; + + return S_OK; +} + +static HRESULT d3d12_bundle_allocator_free_command_buffer(struct d3d12_bundle_allocator *allocator, + struct d3d12_bundle *bundle) +{ + TRACE("allocator %p, bundle %p.\n", allocator, bundle); + + if (allocator->current_bundle == bundle) + allocator->current_bundle = NULL; + + if (!vkd3d_array_reserve((void **)&allocator->arg_buffers, &allocator->arg_buffers_size, + allocator->arg_buffer_count + 1, sizeof(*allocator->arg_buffers))) + { + WARN("Failed to add command buffer.\n"); + vkd3d_free(bundle->command_buffer.commands); + return E_OUTOFMEMORY; + } + + allocator->arg_buffers[allocator->arg_buffer_count++] = bundle->command_buffer.commands; + + return S_OK; +} + +/* ID3D12GraphicsCommandList */ +static inline struct d3d12_bundle *impl_from_ID3D12GraphicsCommandList2(ID3D12GraphicsCommandList2 *iface) +{ + return CONTAINING_RECORD(iface, struct d3d12_bundle, ID3D12GraphicsCommandList2_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_QueryInterface(ID3D12GraphicsCommandList2 *iface, + REFIID iid, void **object) +{ + TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object); + + if (IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList2) + || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList1) + || IsEqualGUID(iid, &IID_ID3D12GraphicsCommandList) + || IsEqualGUID(iid, &IID_ID3D12CommandList) + || IsEqualGUID(iid, &IID_ID3D12DeviceChild) + || IsEqualGUID(iid, &IID_ID3D12Object) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID3D12GraphicsCommandList2_AddRef(iface); + *object = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + + *object = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d3d12_bundle_AddRef(ID3D12GraphicsCommandList2 *iface) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + ULONG refcount = InterlockedIncrement(&bundle->refcount); + + TRACE("%p increasing refcount to %u.\n", bundle, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d3d12_bundle_Release(ID3D12GraphicsCommandList2 *iface) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + ULONG refcount = InterlockedDecrement(&bundle->refcount); + + TRACE("%p decreasing refcount to %u.\n", bundle, refcount); + + if (!refcount) + { + struct d3d12_device *device = bundle->device; + + vkd3d_private_store_destroy(&bundle->private_store); + + if (bundle->allocator) + d3d12_bundle_allocator_free_command_buffer(bundle->allocator, bundle); + + vkd3d_free(bundle); + + d3d12_device_release(device); + } + + return refcount; +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_GetPrivateData(ID3D12GraphicsCommandList2 *iface, + REFGUID guid, UINT *data_size, void *data) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + + TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return vkd3d_get_private_data(&bundle->private_store, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_SetPrivateData(ID3D12GraphicsCommandList2 *iface, + REFGUID guid, UINT data_size, const void *data) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + + TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return vkd3d_set_private_data(&bundle->private_store, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_SetPrivateDataInterface(ID3D12GraphicsCommandList2 *iface, + REFGUID guid, const IUnknown *data) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + + TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data); + + return vkd3d_set_private_data_interface(&bundle->private_store, guid, data); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_SetName(ID3D12GraphicsCommandList2 *iface, const WCHAR *name) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + + TRACE("iface %p, name %s.\n", iface, debugstr_w(name, bundle->device->wchar_size)); + + return name ? S_OK : E_INVALIDARG; +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_GetDevice(ID3D12GraphicsCommandList2 *iface, REFIID iid, void **device) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + + TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device); + + return d3d12_device_query_interface(bundle->device, iid, device); +} + +static D3D12_COMMAND_LIST_TYPE STDMETHODCALLTYPE d3d12_bundle_GetType(ID3D12GraphicsCommandList2 *iface) +{ + TRACE("iface %p.\n", iface); + + return D3D12_COMMAND_LIST_TYPE_BUNDLE; +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_Close(ID3D12GraphicsCommandList2 *iface) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + HRESULT hr = S_OK; + + TRACE("iface %p.\n", iface); + + if (!bundle->is_recording) + { + WARN("Command list is not in the recording state.\n"); + return E_FAIL; + } + + if (bundle->allocator) + { + hr = d3d12_bundle_allocator_free_command_buffer(bundle->allocator, bundle); + bundle->allocator = NULL; + } + + bundle->is_recording = false; + + if (!bundle->is_valid) + { + WARN("Error occurred during command list recording.\n"); + return E_INVALIDARG; + } + + return hr; +} + +static void d3d12_bundle_init_state(struct d3d12_bundle *bundle, ID3D12PipelineState *initial_pipeline_state) +{ + ID3D12GraphicsCommandList2 *iface = &bundle->ID3D12GraphicsCommandList2_iface; + + ID3D12GraphicsCommandList2_SetPipelineState(iface, initial_pipeline_state); + ID3D12GraphicsCommandList2_IASetPrimitiveTopology(iface, D3D_PRIMITIVE_TOPOLOGY_UNDEFINED); +} + +static HRESULT STDMETHODCALLTYPE d3d12_bundle_Reset(ID3D12GraphicsCommandList2 *iface, + ID3D12CommandAllocator *allocator_iface, ID3D12PipelineState *initial_pipeline_state) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + struct d3d12_bundle_allocator *allocator; + HRESULT hr; + + if (!allocator_iface) + { + WARN("Command allocator is NULL.\n"); + return E_INVALIDARG; + } + + if (!(allocator = checked_impl_from_ID3D12CommandAllocator(allocator_iface))) + { + WARN("Command allocator is not of type D3D12_COMMAND_LIST_TYPE_BUNDLE.\n"); + return E_INVALIDARG; + } + + if (bundle->is_recording) + { + WARN("Command list is in the recording state.\n"); + return E_FAIL; + } + + if (SUCCEEDED(hr = d3d12_bundle_allocator_init_command_buffer(allocator, bundle))) + { + bundle->allocator = allocator; + d3d12_bundle_init_state(bundle, initial_pipeline_state); + } + + return hr; +} + +static void d3d12_bundle_mark_as_invalid(ID3D12GraphicsCommandList2 *iface) +{ + impl_from_ID3D12GraphicsCommandList2(iface)->is_valid = false; +} + +static void STDMETHODCALLTYPE d3d12_bundle_ClearState(ID3D12GraphicsCommandList2 *iface, + ID3D12PipelineState *pipeline_state) +{ + ERR("iface %p, pipline_state %p command invalid for bundles.\n", iface, pipeline_state); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_DrawInstanced(ID3D12GraphicsCommandList2 *iface, + UINT vertex_count_per_instance, UINT instance_count, UINT start_vertex_location, + UINT start_instance_location) +{ + struct d3d12_bundle *bundle = impl_from_ID3D12GraphicsCommandList2(iface); + struct d3d12_bundle_command_buffer *buffer = &bundle->command_buffer; + + TRACE("iface %p, vertex_count_per_instance %u, instance_count %u, start_vertex_location %u, " + "start_instance_location %u.\n", iface, vertex_count_per_instance, instance_count, + start_vertex_location, start_instance_location); + + if (!d3d12_bundle_command_buffer_reserve(buffer, 4, VKD3D_COMMAND_DRAW_INSTANCED)) + return; + + buffer->commands[buffer->count++].uint_arg = vertex_count_per_instance; + buffer->commands[buffer->count++].uint_arg = instance_count; + buffer->commands[buffer->count++].uint_arg = start_vertex_location; + buffer->commands[buffer->count++].uint_arg = start_instance_location; +} + +static void STDMETHODCALLTYPE d3d12_bundle_DrawIndexedInstanced(ID3D12GraphicsCommandList2 *iface, + UINT index_count_per_instance, UINT instance_count, UINT start_vertex_location, + INT base_vertex_location, UINT start_instance_location) +{ + FIXME("iface %p, index_count_per_instance %u, instance_count %u, start_vertex_location %u, " + "base_vertex_location %d, start_instance_location %u stub!\n", iface, index_count_per_instance, + instance_count, start_vertex_location, base_vertex_location, start_instance_location); +} + +static void STDMETHODCALLTYPE d3d12_bundle_Dispatch(ID3D12GraphicsCommandList2 *iface, + UINT x, UINT y, UINT z) +{ + FIXME("iface %p, x %u, y %u, z %u stub!\n", iface, x, y, z); +} + +static void STDMETHODCALLTYPE d3d12_bundle_CopyBufferRegion(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *dst, UINT64 dst_offset, ID3D12Resource *src, UINT64 src_offset, UINT64 byte_count) +{ + ERR("iface %p, dst_resource %p, dst_offset %#"PRIx64", src_resource %p, " + "src_offset %#"PRIx64", byte_count %#"PRIx64" command invalid for bundles.\n", + iface, dst, dst_offset, src, src_offset, byte_count); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_CopyTextureRegion(ID3D12GraphicsCommandList2 *iface, + const D3D12_TEXTURE_COPY_LOCATION *dst, UINT dst_x, UINT dst_y, UINT dst_z, + const D3D12_TEXTURE_COPY_LOCATION *src, const D3D12_BOX *src_box) +{ + ERR("iface %p, dst %p, dst_x %u, dst_y %u, dst_z %u, src %p, src_box %p command invalid for bundles.\n", + iface, dst, dst_x, dst_y, dst_z, src, src_box); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_CopyResource(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *dst, ID3D12Resource *src) +{ + ERR("iface %p, dst_resource %p, src_resource %p command invalid for bundles.\n", iface, dst, src); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_CopyTiles(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *tiled_resource, const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate, + const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer, UINT64 buffer_offset, + D3D12_TILE_COPY_FLAGS flags) +{ + ERR("iface %p, tiled_resource %p, tile_region_start_coordinate %p, tile_region_size %p, " + "buffer %p, buffer_offset %#"PRIx64", flags %#x command invalid for bundles.\n", + iface, tiled_resource, tile_region_start_coordinate, tile_region_size, + buffer, buffer_offset, flags); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ResolveSubresource(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *dst, UINT dst_sub_resource_idx, + ID3D12Resource *src, UINT src_sub_resource_idx, DXGI_FORMAT format) +{ + ERR("iface %p, dst_resource %p, dst_sub_resource_idx %u, src_resource %p, src_sub_resource_idx %u, format %#x " + "command invalid for bundles.\n", iface, dst, dst_sub_resource_idx, src, src_sub_resource_idx, format); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_IASetPrimitiveTopology(ID3D12GraphicsCommandList2 *iface, + D3D12_PRIMITIVE_TOPOLOGY topology) +{ + FIXME("iface %p, topology %#x stub!\n", iface, topology); +} + +static void STDMETHODCALLTYPE d3d12_bundle_RSSetViewports(ID3D12GraphicsCommandList2 *iface, + UINT viewport_count, const D3D12_VIEWPORT *viewports) +{ + ERR("iface %p, viewport_count %u, viewports %p command invalid for bundles.\n", iface, viewport_count, viewports); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_RSSetScissorRects(ID3D12GraphicsCommandList2 *iface, + UINT rect_count, const D3D12_RECT *rects) +{ + ERR("iface %p, rect_count %u, rects %p command invalid for bundles.\n", iface, rect_count, rects); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_OMSetBlendFactor(ID3D12GraphicsCommandList2 *iface, + const FLOAT blend_factor[4]) +{ + FIXME("iface %p, blend_factor %p stub!\n", iface, blend_factor); +} + +static void STDMETHODCALLTYPE d3d12_bundle_OMSetStencilRef(ID3D12GraphicsCommandList2 *iface, UINT stencil_ref) +{ + FIXME("iface %p, stencil_ref %u stub!\n", iface, stencil_ref); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetPipelineState(ID3D12GraphicsCommandList2 *iface, + ID3D12PipelineState *pipeline_state) +{ + FIXME("iface %p, pipeline_state %p stub!\n", iface, pipeline_state); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ResourceBarrier(ID3D12GraphicsCommandList2 *iface, + UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers) +{ + ERR("iface %p, barrier_count %u, barriers %p command invalid for bundles.\n", iface, barrier_count, barriers); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ExecuteBundle(ID3D12GraphicsCommandList2 *iface, + ID3D12GraphicsCommandList *bundle_iface) +{ + ERR("iface %p, bundle_iface %p command invalid for bundles.\n", iface, bundle_iface); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetDescriptorHeaps(ID3D12GraphicsCommandList2 *iface, + UINT heap_count, ID3D12DescriptorHeap *const *heaps) +{ + TRACE("iface %p, heap_count %u, heaps %p.\n", iface, heap_count, heaps); + + /* Our current implementation does not need this method. + * + * The D3D12 documentation states it is valid for bundles if the heaps are the same as + * those already set in the executing command list. ExecuteBundle() could validate this + * but we do not have an equivalent of the D3D12 Debug Layer. */ +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRootSignature(ID3D12GraphicsCommandList2 *iface, + ID3D12RootSignature *root_signature) +{ + FIXME("iface %p, root_signature %p stub!\n", iface, root_signature); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRootSignature(ID3D12GraphicsCommandList2 *iface, + ID3D12RootSignature *root_signature) +{ + FIXME("iface %p, root_signature %p stub!\n", iface, root_signature); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList2 *iface, + UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) +{ + FIXME("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64" stub!\n", + iface, root_parameter_index, base_descriptor.ptr); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList2 *iface, + UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) +{ + FIXME("iface %p, root_parameter_index %u, base_descriptor %#"PRIx64" stub!\n", + iface, root_parameter_index, base_descriptor.ptr); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList2 *iface, + UINT root_parameter_index, UINT data, UINT dst_offset) +{ + FIXME("iface %p, root_parameter_index %u, data 0x%08x, dst_offset %u stub!\n", + iface, root_parameter_index, data, dst_offset); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList2 *iface, + UINT root_parameter_index, UINT data, UINT dst_offset) +{ + FIXME("iface %p, root_parameter_index %u, data 0x%08x, dst_offset %u stub!\n", + iface, root_parameter_index, data, dst_offset); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList2 *iface, + UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset) +{ + FIXME("iface %p, root_parameter_index %u, constant_count %u, data %p, dst_offset %u stub!\n", + iface, root_parameter_index, constant_count, data, dst_offset); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList2 *iface, + UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset) +{ + FIXME("iface %p, root_parameter_index %u, constant_count %u, data %p, dst_offset %u stub!\n", + iface, root_parameter_index, constant_count, data, dst_offset); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRootConstantBufferView( + ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) +{ + FIXME("iface %p, root_parameter_index %u, address %#"PRIx64" stub!\n", iface, root_parameter_index, address); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRootConstantBufferView( + ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) +{ + FIXME("iface %p, root_parameter_index %u, address %#"PRIx64" stub!\n", iface, root_parameter_index, address); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRootShaderResourceView( + ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) +{ + FIXME("iface %p, root_parameter_index %u, address %#"PRIx64" stub!\n", iface, root_parameter_index, address); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRootShaderResourceView( + ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) +{ + FIXME("iface %p, root_parameter_index %u, address %#"PRIx64" stub!\n", iface, root_parameter_index, address); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetComputeRootUnorderedAccessView( + ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) +{ + FIXME("iface %p, root_parameter_index %u, address %#"PRIx64" stub!\n", iface, root_parameter_index, address); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetGraphicsRootUnorderedAccessView( + ID3D12GraphicsCommandList2 *iface, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) +{ + FIXME("iface %p, root_parameter_index %u, address %#"PRIx64" stub!\n", iface, root_parameter_index, address); +} + +static void STDMETHODCALLTYPE d3d12_bundle_IASetIndexBuffer(ID3D12GraphicsCommandList2 *iface, + const D3D12_INDEX_BUFFER_VIEW *view) +{ + FIXME("iface %p, view %p stub!\n", iface, view); +} + +static void STDMETHODCALLTYPE d3d12_bundle_IASetVertexBuffers(ID3D12GraphicsCommandList2 *iface, + UINT start_slot, UINT view_count, const D3D12_VERTEX_BUFFER_VIEW *views) +{ + FIXME("iface %p, start_slot %u, view_count %u, views %p stub!\n", iface, start_slot, view_count, views); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SOSetTargets(ID3D12GraphicsCommandList2 *iface, + UINT start_slot, UINT view_count, const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) +{ + ERR("iface %p, start_slot %u, view_count %u, views %p command invalid for bundles.\n", + iface, start_slot, view_count, views); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_OMSetRenderTargets(ID3D12GraphicsCommandList2 *iface, + UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, + BOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) +{ + ERR("iface %p, render_target_descriptor_count %u, render_target_descriptors %p, " + "single_descriptor_handle %#x, depth_stencil_descriptor %p command invalid for bundles.\n", + iface, render_target_descriptor_count, render_target_descriptors, + single_descriptor_handle, depth_stencil_descriptor); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ClearDepthStencilView(ID3D12GraphicsCommandList2 *iface, + D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags, float depth, UINT8 stencil, + UINT rect_count, const D3D12_RECT *rects) +{ + ERR("iface %p, dsv %#lx, flags %#x, depth %.8e, stencil 0x%02x, rect_count %u, rects %p " + "command invalid for bundles.\n", iface, dsv.ptr, flags, depth, stencil, rect_count, rects); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ClearRenderTargetView(ID3D12GraphicsCommandList2 *iface, + D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4], UINT rect_count, const D3D12_RECT *rects) +{ + ERR("iface %p, rtv %#lx, color %p, rect_count %u, rects %p command invalid for bundles.\n", + iface, rtv.ptr, color, rect_count, rects); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList2 *iface, + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, + const UINT values[4], UINT rect_count, const D3D12_RECT *rects) +{ + ERR("iface %p, gpu_handle %#"PRIx64", cpu_handle %lx, resource %p, values %p, rect_count %u, rects %p command " + "invalid for bundles.\n", iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList2 *iface, + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, + const float values[4], UINT rect_count, const D3D12_RECT *rects) +{ + ERR("iface %p, gpu_handle %#"PRIx64", cpu_handle %lx, resource %p, values %p, rect_count %u, rects %p command " + "invalid for bundles.\n", iface, gpu_handle.ptr, cpu_handle.ptr, resource, values, rect_count, rects); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_DiscardResource(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *resource, const D3D12_DISCARD_REGION *region) +{ + ERR("iface %p, resource %p, region %p command invalid for bundles.\n", iface, resource, region); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_BeginQuery(ID3D12GraphicsCommandList2 *iface, + ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index) +{ + ERR("iface %p, heap %p, type %#x, index %u command invalid for bundles.\n", iface, heap, type, index); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_EndQuery(ID3D12GraphicsCommandList2 *iface, + ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index) +{ + ERR("iface %p, heap %p, type %#x, index %u command invalid for bundles.\n", iface, heap, type, index); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ResolveQueryData(ID3D12GraphicsCommandList2 *iface, + ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count, + ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset) +{ + ERR("iface %p, heap %p, type %#x, start_index %u, query_count %u, " + "dst_buffer %p, aligned_dst_buffer_offset %#"PRIx64" command invalid for bundles.\n", + iface, heap, type, start_index, query_count, dst_buffer, aligned_dst_buffer_offset); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetPredication(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *buffer, UINT64 aligned_buffer_offset, D3D12_PREDICATION_OP operation) +{ + ERR("iface %p, buffer %p, aligned_buffer_offset %#"PRIx64", operation %#x command invalid for bundles.\n", + iface, buffer, aligned_buffer_offset, operation); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetMarker(ID3D12GraphicsCommandList2 *iface, + UINT metadata, const void *data, UINT size) +{ + /* Undocumented function used by Microsoft's PIX event runtime. Validity for bundles unknown. */ + FIXME("iface %p, metadata %#x, data %p, size %u stub!\n", iface, metadata, data, size); +} + +static void STDMETHODCALLTYPE d3d12_bundle_BeginEvent(ID3D12GraphicsCommandList2 *iface, + UINT metadata, const void *data, UINT size) +{ + /* Undocumented function used by Microsoft's PIX event runtime. Validity for bundles unknown. */ + FIXME("iface %p, metadata %#x, data %p, size %u stub!\n", iface, metadata, data, size); +} + +static void STDMETHODCALLTYPE d3d12_bundle_EndEvent(ID3D12GraphicsCommandList2 *iface) +{ + /* Undocumented function used by Microsoft's PIX event runtime. Validity for bundles unknown. */ + FIXME("iface %p stub!\n", iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ExecuteIndirect(ID3D12GraphicsCommandList2 *iface, + 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", + iface, command_signature, max_command_count, arg_buffer, arg_buffer_offset, + count_buffer, count_buffer_offset); +} + +static void STDMETHODCALLTYPE d3d12_bundle_AtomicCopyBufferUINT(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *dst_buffer, UINT64 dst_offset, + ID3D12Resource *src_buffer, UINT64 src_offset, + UINT dependent_resource_count, ID3D12Resource * const *dependent_resources, + const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) +{ + ERR("iface %p, dst_resource %p, dst_offset %#"PRIx64", src_resource %p, " + "src_offset %#"PRIx64", dependent_resource_count %u, " + "dependent_resources %p, dependent_sub_resource_ranges %p command invalid for bundles.\n", + iface, dst_buffer, dst_offset, src_buffer, src_offset, + dependent_resource_count, dependent_resources, dependent_sub_resource_ranges); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *dst_buffer, UINT64 dst_offset, + ID3D12Resource *src_buffer, UINT64 src_offset, + UINT dependent_resource_count, ID3D12Resource * const *dependent_resources, + const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) +{ + ERR("iface %p, dst_resource %p, dst_offset %#"PRIx64", src_resource %p, " + "src_offset %#"PRIx64", dependent_resource_count %u, " + "dependent_resources %p, dependent_sub_resource_ranges %p command invalid for bundles.\n", + iface, dst_buffer, dst_offset, src_buffer, src_offset, + dependent_resource_count, dependent_resources, dependent_sub_resource_ranges); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_OMSetDepthBounds(ID3D12GraphicsCommandList2 *iface, + FLOAT min, FLOAT max) +{ + FIXME("iface %p, min %.8e, max %.8e stub!\n", iface, min, max); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetSamplePositions(ID3D12GraphicsCommandList2 *iface, + UINT sample_count, UINT pixel_count, D3D12_SAMPLE_POSITION *sample_positions) +{ + FIXME("iface %p, sample_count %u, pixel_count %u, sample_positions %p stub!\n", + iface, sample_count, pixel_count, sample_positions); +} + +static void STDMETHODCALLTYPE d3d12_bundle_ResolveSubresourceRegion(ID3D12GraphicsCommandList2 *iface, + ID3D12Resource *dst_resource, UINT dst_sub_resource_idx, UINT dst_x, UINT dst_y, + ID3D12Resource *src_resource, UINT src_sub_resource_idx, + D3D12_RECT *src_rect, DXGI_FORMAT format, D3D12_RESOLVE_MODE mode) +{ + ERR("iface %p, dst_resource %p, dst_sub_resource_idx %u, " + "dst_x %u, dst_y %u, src_resource %p, src_sub_resource_idx %u, " + "src_rect %p, format %#x, mode %#x command invalid for bundles.\n", + iface, dst_resource, dst_sub_resource_idx, dst_x, dst_y, + src_resource, src_sub_resource_idx, src_rect, format, mode); + + d3d12_bundle_mark_as_invalid(iface); +} + +static void STDMETHODCALLTYPE d3d12_bundle_SetViewInstanceMask(ID3D12GraphicsCommandList2 *iface, UINT mask) +{ + FIXME("iface %p, mask %#x stub!\n", iface, mask); +} + +static void STDMETHODCALLTYPE d3d12_bundle_WriteBufferImmediate(ID3D12GraphicsCommandList2 *iface, + UINT count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters, + const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes) +{ + FIXME("iface %p, count %u, parameters %p, modes %p stub!\n", iface, count, parameters, modes); +} + +static const struct ID3D12GraphicsCommandList2Vtbl d3d12_bundle_vtbl = +{ + /* IUnknown methods */ + d3d12_bundle_QueryInterface, + d3d12_bundle_AddRef, + d3d12_bundle_Release, + /* ID3D12Object methods */ + d3d12_bundle_GetPrivateData, + d3d12_bundle_SetPrivateData, + d3d12_bundle_SetPrivateDataInterface, + d3d12_bundle_SetName, + /* ID3D12DeviceChild methods */ + d3d12_bundle_GetDevice, + /* ID3D12CommandList methods */ + d3d12_bundle_GetType, + /* ID3D12GraphicsCommandList methods */ + d3d12_bundle_Close, + d3d12_bundle_Reset, + d3d12_bundle_ClearState, + d3d12_bundle_DrawInstanced, + d3d12_bundle_DrawIndexedInstanced, + d3d12_bundle_Dispatch, + d3d12_bundle_CopyBufferRegion, + d3d12_bundle_CopyTextureRegion, + d3d12_bundle_CopyResource, + d3d12_bundle_CopyTiles, + d3d12_bundle_ResolveSubresource, + d3d12_bundle_IASetPrimitiveTopology, + d3d12_bundle_RSSetViewports, + d3d12_bundle_RSSetScissorRects, + d3d12_bundle_OMSetBlendFactor, + d3d12_bundle_OMSetStencilRef, + d3d12_bundle_SetPipelineState, + d3d12_bundle_ResourceBarrier, + d3d12_bundle_ExecuteBundle, + d3d12_bundle_SetDescriptorHeaps, + d3d12_bundle_SetComputeRootSignature, + d3d12_bundle_SetGraphicsRootSignature, + d3d12_bundle_SetComputeRootDescriptorTable, + d3d12_bundle_SetGraphicsRootDescriptorTable, + d3d12_bundle_SetComputeRoot32BitConstant, + d3d12_bundle_SetGraphicsRoot32BitConstant, + d3d12_bundle_SetComputeRoot32BitConstants, + d3d12_bundle_SetGraphicsRoot32BitConstants, + d3d12_bundle_SetComputeRootConstantBufferView, + d3d12_bundle_SetGraphicsRootConstantBufferView, + d3d12_bundle_SetComputeRootShaderResourceView, + d3d12_bundle_SetGraphicsRootShaderResourceView, + d3d12_bundle_SetComputeRootUnorderedAccessView, + d3d12_bundle_SetGraphicsRootUnorderedAccessView, + d3d12_bundle_IASetIndexBuffer, + d3d12_bundle_IASetVertexBuffers, + d3d12_bundle_SOSetTargets, + d3d12_bundle_OMSetRenderTargets, + d3d12_bundle_ClearDepthStencilView, + d3d12_bundle_ClearRenderTargetView, + d3d12_bundle_ClearUnorderedAccessViewUint, + d3d12_bundle_ClearUnorderedAccessViewFloat, + d3d12_bundle_DiscardResource, + d3d12_bundle_BeginQuery, + d3d12_bundle_EndQuery, + d3d12_bundle_ResolveQueryData, + d3d12_bundle_SetPredication, + d3d12_bundle_SetMarker, + d3d12_bundle_BeginEvent, + d3d12_bundle_EndEvent, + d3d12_bundle_ExecuteIndirect, + /* ID3D12GraphicsCommandList1 methods */ + d3d12_bundle_AtomicCopyBufferUINT, + d3d12_bundle_AtomicCopyBufferUINT64, + d3d12_bundle_OMSetDepthBounds, + d3d12_bundle_SetSamplePositions, + d3d12_bundle_ResolveSubresourceRegion, + d3d12_bundle_SetViewInstanceMask, + /* ID3D12GraphicsCommandList2 methods */ + d3d12_bundle_WriteBufferImmediate, +}; + +struct d3d12_bundle *bundle_impl_from_ID3D12GraphicsCommandList(ID3D12GraphicsCommandList *iface) +{ + if (!iface || iface->lpVtbl != (struct ID3D12GraphicsCommandListVtbl *)&d3d12_bundle_vtbl) + return NULL; + + return impl_from_ID3D12GraphicsCommandList2((ID3D12GraphicsCommandList2 *)iface); +} + +static HRESULT d3d12_bundle_init(struct d3d12_bundle *bundle, struct d3d12_device *device, + struct d3d12_bundle_allocator *allocator, ID3D12PipelineState *initial_pipeline_state) +{ + HRESULT hr; + + bundle->ID3D12GraphicsCommandList2_iface.lpVtbl = &d3d12_bundle_vtbl; + bundle->refcount = 1; + + if (FAILED(hr = vkd3d_private_store_init(&bundle->private_store))) + return hr; + + bundle->allocator = allocator; + + if (SUCCEEDED(hr = d3d12_bundle_allocator_init_command_buffer(allocator, bundle))) + { + d3d12_device_add_ref(bundle->device = device); + d3d12_bundle_init_state(bundle, initial_pipeline_state); + } + else + { + vkd3d_private_store_destroy(&bundle->private_store); + } + + return hr; +} + +HRESULT d3d12_bundle_create(struct d3d12_device *device, + UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *allocator_iface, + ID3D12PipelineState *initial_pipeline_state, struct d3d12_bundle **bundle) +{ + struct d3d12_bundle_allocator *allocator; + struct d3d12_bundle *object; + HRESULT hr; + + if (!allocator_iface) + { + WARN("Command allocator is NULL.\n"); + return E_INVALIDARG; + } + + if (!(allocator = checked_impl_from_ID3D12CommandAllocator(allocator_iface))) + { + WARN("Command allocator is not of type D3D12_COMMAND_LIST_TYPE_BUNDLE.\n"); + return E_INVALIDARG; + } + + debug_ignored_node_mask(node_mask); + + if (!(object = vkd3d_calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + if (FAILED(hr = d3d12_bundle_init(object, device, allocator, initial_pipeline_state))) + { + vkd3d_free(object); + return hr; + } + + TRACE("Created command list %p.\n", object); + + *bundle = object; + + return S_OK; +} diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 253b9128..2a6d0b76 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -4049,10 +4049,51 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC WARN("Issuing split barrier(s) on D3D12_RESOURCE_BARRIER_FLAG_END_ONLY.\n"); } +static void d3d12_bundle_command_execute(unsigned int id, const union d3d12_bundle_command_arg *args, + ID3D12GraphicsCommandList2 *list); + static void STDMETHODCALLTYPE d3d12_command_list_ExecuteBundle(ID3D12GraphicsCommandList2 *iface, - ID3D12GraphicsCommandList *command_list) + ID3D12GraphicsCommandList *bundle_iface) { - FIXME("iface %p, command_list %p stub!\n", iface, command_list); + const struct d3d12_bundle *bundle = bundle_impl_from_ID3D12GraphicsCommandList(bundle_iface); + struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList2(iface); + const union d3d12_bundle_command_arg *commands; + enum vkd3d_command_list_command_id id; + unsigned int count; + size_t i; + + TRACE("iface %p, bundle_iface %p.\n", iface, bundle_iface); + + if (!bundle) + { + WARN("bundle_iface is not a bundle.\n"); + list->is_valid = false; + return; + } + + if (!bundle->is_valid) + { + WARN("Error occurred during bundle recording.\n"); + list->is_valid = false; + return; + } + + if (bundle->is_recording) + { + WARN("Bundle is in the recording state.\n"); + list->is_valid = false; + return; + } + + commands = bundle->command_buffer.commands; + + for (i = 0; i < bundle->command_buffer.count; i += count) + { + count = commands[i].header.count; + id = commands[i++].header.id; + d3d12_bundle_command_execute(id, &commands[i], iface); + } + assert(i == bundle->command_buffer.count); } static void STDMETHODCALLTYPE d3d12_command_list_SetDescriptorHeaps(ID3D12GraphicsCommandList2 *iface, @@ -5614,6 +5655,21 @@ static struct d3d12_command_list *unsafe_impl_from_ID3D12CommandList(ID3D12Comma return CONTAINING_RECORD(iface, struct d3d12_command_list, ID3D12GraphicsCommandList2_iface); } +static void d3d12_bundle_command_execute(enum vkd3d_command_list_command_id id, + const union d3d12_bundle_command_arg *args, ID3D12GraphicsCommandList2 *list) +{ + switch (id) + { + case VKD3D_COMMAND_DRAW_INSTANCED: + d3d12_command_list_DrawInstanced(list, args[0].uint_arg, args[1].uint_arg, + args[2].uint_arg, args[3].uint_arg); + break; + default: + FIXME("Unhandled command %u.\n", id); + break; + } +} + static HRESULT d3d12_command_list_init(struct d3d12_command_list *list, struct d3d12_device *device, D3D12_COMMAND_LIST_TYPE type, struct d3d12_command_allocator *allocator, ID3D12PipelineState *initial_pipeline_state) diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 0fadb521..3ff1affb 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -2314,17 +2314,29 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandAllocator(ID3D12Devic D3D12_COMMAND_LIST_TYPE type, REFIID riid, void **command_allocator) { struct d3d12_device *device = impl_from_ID3D12Device(iface); - struct d3d12_command_allocator *object; HRESULT hr; TRACE("iface %p, type %#x, riid %s, command_allocator %p.\n", iface, type, debugstr_guid(riid), command_allocator); - if (FAILED(hr = d3d12_command_allocator_create(device, type, &object))) - return hr; + if (type == D3D12_COMMAND_LIST_TYPE_BUNDLE) + { + struct d3d12_bundle_allocator *object; + if (FAILED(hr = d3d12_bundle_allocator_create(device, &object))) + return hr; - return return_interface(&object->ID3D12CommandAllocator_iface, &IID_ID3D12CommandAllocator, - riid, command_allocator); + return return_interface(&object->ID3D12CommandAllocator_iface, + &IID_ID3D12CommandAllocator, riid, command_allocator); + } + else + { + struct d3d12_command_allocator *object; + if (FAILED(hr = d3d12_command_allocator_create(device, type, &object))) + return hr; + + return return_interface(&object->ID3D12CommandAllocator_iface, + &IID_ID3D12CommandAllocator, riid, command_allocator); + } } static HRESULT STDMETHODCALLTYPE d3d12_device_CreateGraphicsPipelineState(ID3D12Device *iface, @@ -2366,7 +2378,6 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList(ID3D12Device *if ID3D12PipelineState *initial_pipeline_state, REFIID riid, void **command_list) { struct d3d12_device *device = impl_from_ID3D12Device(iface); - struct d3d12_command_list *object; HRESULT hr; TRACE("iface %p, node_mask 0x%08x, type %#x, command_allocator %p, " @@ -2374,12 +2385,26 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreateCommandList(ID3D12Device *if iface, node_mask, type, command_allocator, initial_pipeline_state, debugstr_guid(riid), command_list); - if (FAILED(hr = d3d12_command_list_create(device, node_mask, type, command_allocator, - initial_pipeline_state, &object))) - return hr; + if (type == D3D12_COMMAND_LIST_TYPE_BUNDLE) + { + struct d3d12_bundle *object; + if (FAILED(hr = d3d12_bundle_create(device, node_mask, type, command_allocator, + initial_pipeline_state, &object))) + return hr; - return return_interface(&object->ID3D12GraphicsCommandList2_iface, - &IID_ID3D12GraphicsCommandList2, riid, command_list); + return return_interface(&object->ID3D12GraphicsCommandList2_iface, + &IID_ID3D12GraphicsCommandList2, riid, command_list); + } + else + { + struct d3d12_command_list *object; + if (FAILED(hr = d3d12_command_list_create(device, node_mask, type, command_allocator, + initial_pipeline_state, &object))) + return hr; + + return return_interface(&object->ID3D12GraphicsCommandList2_iface, + &IID_ID3D12GraphicsCommandList2, riid, command_list); + } } /* Direct3D feature levels restrict which formats can be optionally supported. */ diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 0b326b11..1d5fab65 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -987,6 +987,82 @@ HRESULT d3d12_command_list_create(struct d3d12_device *device, UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *allocator_iface, ID3D12PipelineState *initial_pipeline_state, struct d3d12_command_list **list); +enum vkd3d_command_list_command_id +{ + VKD3D_COMMAND_DRAW_INSTANCED, +}; + +struct d3d12_bundle_command_header +{ + unsigned int count; + enum vkd3d_command_list_command_id id; +}; + +union d3d12_bundle_command_arg +{ + struct d3d12_bundle_command_header header; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_descriptor_handle; + D3D12_GPU_VIRTUAL_ADDRESS gpu_address; + D3D12_PRIMITIVE_TOPOLOGY topology; + float float_arg; + ID3D12CommandSignature *command_signature; + ID3D12PipelineState *pipeline_state; + ID3D12Resource *resource; + ID3D12RootSignature *root_signature; + int int_arg; + uint64_t uint64_arg; + unsigned int uint_arg; +}; + +#define d3d12_bundle_command_arg_count_from_sizeof(size) \ + (((size) + sizeof(union d3d12_bundle_command_arg) - 1) / sizeof(union d3d12_bundle_command_arg)) + +struct d3d12_bundle_command_buffer +{ + union d3d12_bundle_command_arg *commands; + size_t size; + size_t count; +}; + +struct d3d12_bundle_allocator +{ + ID3D12CommandAllocator ID3D12CommandAllocator_iface; + LONG refcount; + + union d3d12_bundle_command_arg **arg_buffers; + size_t arg_buffers_size; + size_t arg_buffer_count; + + struct d3d12_bundle *current_bundle; + struct d3d12_device *device; + + struct vkd3d_private_store private_store; +}; + +HRESULT d3d12_bundle_allocator_create(struct d3d12_device *device, + struct d3d12_bundle_allocator **allocator); + +struct d3d12_bundle +{ + ID3D12GraphicsCommandList2 ID3D12GraphicsCommandList2_iface; + LONG refcount; + + bool is_recording; + bool is_valid; + struct d3d12_bundle_command_buffer command_buffer; + + struct d3d12_device *device; + struct d3d12_bundle_allocator *allocator; + + struct vkd3d_private_store private_store; +}; + +struct d3d12_bundle *bundle_impl_from_ID3D12GraphicsCommandList(ID3D12GraphicsCommandList *iface); + +HRESULT d3d12_bundle_create(struct d3d12_device *device, + UINT node_mask, D3D12_COMMAND_LIST_TYPE type, ID3D12CommandAllocator *allocator_iface, + ID3D12PipelineState *initial_pipeline_state, struct d3d12_bundle **bundle); + struct vkd3d_queue { /* Access to VkQueue must be externally synchronized. */ diff --git a/tests/d3d12.c b/tests/d3d12.c index 1e895dcd..f723dbaa 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -7380,13 +7380,6 @@ static void test_bundle_state_inheritance(void) unsigned int x, y; HRESULT hr; - if (!vkd3d_test_platform_is_windows()) - { - /* FIXME: Avoid 2048 test todos. */ - skip("Bundles are not implemented yet.\n"); - return; - } - if (use_warp_device) { skip("Bundle state inheritance test crashes on WARP.\n"); @@ -7569,6 +7562,7 @@ static void test_bundle_state_inheritance(void) transition_resource_state(command_list, context.render_target, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); + todo check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0); reset_command_list(command_list, context.allocator); @@ -7594,6 +7588,7 @@ static void test_bundle_state_inheritance(void) transition_resource_state(command_list, context.render_target, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE); + todo check_sub_resource_uint(context.render_target, 0, queue, command_list, 0xff00ff00, 0); ID3D12CommandAllocator_Release(bundle_allocator); -- 2.32.0