Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/d3d11/d3d11_private.h | 10 +++ dlls/d3d11/device.c | 154 ++++++++++++++++++++++++++++++++++++- dlls/wined3d/cs.c | 103 +++++++++++++++++++++++++ dlls/wined3d/wined3d.spec | 4 + include/wine/wined3d.h | 6 ++ 5 files changed, 276 insertions(+), 1 deletion(-)
diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h index 2b5a51afbd1..afbde9a4bfb 100644 --- a/dlls/d3d11/d3d11_private.h +++ b/dlls/d3d11/d3d11_private.h @@ -583,6 +583,16 @@ struct d3d_device SIZE_T context_state_count; };
+struct d3d11_command_list +{ + ID3D11CommandList ID3D11CommandList_iface; + LONG refcount; + + ID3D11Device2 *device; + struct wined3d_command_list *wined3d_list; + struct wined3d_private_store private_store; +}; + static inline struct d3d_device *impl_from_ID3D11Device(ID3D11Device *iface) { return CONTAINING_RECORD((ID3D11Device2 *)iface, struct d3d_device, ID3D11Device2_iface); diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 6f07bc92cdf..e832d8e68d3 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -330,6 +330,123 @@ static void d3d_device_context_state_init(struct d3d_device_context_state *state d3d_device_context_state_AddRef(&state->ID3DDeviceContextState_iface); }
+/* ID3D11CommandList methods */ + +static inline struct d3d11_command_list *impl_from_ID3D11CommandList(ID3D11CommandList *iface) +{ + return CONTAINING_RECORD(iface, struct d3d11_command_list, ID3D11CommandList_iface); +} + +static HRESULT STDMETHODCALLTYPE d3d11_command_list_QueryInterface(ID3D11CommandList *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_ID3D11CommandList) + || IsEqualGUID(iid, &IID_ID3D11DeviceChild) + || IsEqualGUID(iid, &IID_IUnknown)) + { + ID3D11CommandList_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE d3d11_command_list_AddRef(ID3D11CommandList *iface) +{ + struct d3d11_command_list *list = impl_from_ID3D11CommandList(iface); + ULONG refcount = InterlockedIncrement(&list->refcount); + + TRACE("%p increasing refcount to %u.\n", list, refcount); + + return refcount; +} + +static ULONG STDMETHODCALLTYPE d3d11_command_list_Release(ID3D11CommandList *iface) +{ + struct d3d11_command_list *list = impl_from_ID3D11CommandList(iface); + ULONG refcount = InterlockedDecrement(&list->refcount); + + TRACE("%p decreasing refcount to %u.\n", list, refcount); + + if (!refcount) + { + wined3d_mutex_lock(); + wined3d_command_list_decref(list->wined3d_list); + wined3d_mutex_unlock(); + ID3D11Device2_Release(list->device); + heap_free(list); + } + + return refcount; +} + +static void STDMETHODCALLTYPE d3d11_command_list_GetDevice(ID3D11CommandList *iface, ID3D11Device **device) +{ + struct d3d11_command_list *list = impl_from_ID3D11CommandList(iface); + + TRACE("iface %p, device %p.\n", iface, device); + + *device = (ID3D11Device *)list->device; + ID3D11Device2_AddRef(list->device); +} + +static HRESULT STDMETHODCALLTYPE d3d11_command_list_GetPrivateData(ID3D11CommandList *iface, REFGUID guid, + UINT *data_size, void *data) +{ + struct d3d11_command_list *list = impl_from_ID3D11CommandList(iface); + + TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return d3d_get_private_data(&list->private_store, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE d3d11_command_list_SetPrivateData(ID3D11CommandList *iface, REFGUID guid, + UINT data_size, const void *data) +{ + struct d3d11_command_list *list = impl_from_ID3D11CommandList(iface); + + TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return d3d_set_private_data(&list->private_store, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE d3d11_command_list_SetPrivateDataInterface(ID3D11CommandList *iface, + REFGUID guid, const IUnknown *data) +{ + struct d3d11_command_list *list = impl_from_ID3D11CommandList(iface); + + TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data); + + return d3d_set_private_data_interface(&list->private_store, guid, data); +} + +static UINT STDMETHODCALLTYPE d3d11_command_list_GetContextFlags(ID3D11CommandList *iface) +{ + TRACE("iface %p.\n", iface); + + return 0; +} + +static const struct ID3D11CommandListVtbl d3d11_command_list_vtbl = +{ + /* IUnknown methods */ + d3d11_command_list_QueryInterface, + d3d11_command_list_AddRef, + d3d11_command_list_Release, + /* ID3D11DeviceChild methods */ + d3d11_command_list_GetDevice, + d3d11_command_list_GetPrivateData, + d3d11_command_list_SetPrivateData, + d3d11_command_list_SetPrivateDataInterface, + /* ID3D11CommandList methods */ + d3d11_command_list_GetContextFlags, +}; + /* ID3D11DeviceContext - immediate context methods */
static inline struct d3d11_device_context *impl_from_ID3D11DeviceContext1(ID3D11DeviceContext1 *iface) @@ -2629,9 +2746,44 @@ static UINT STDMETHODCALLTYPE d3d11_device_context_GetContextFlags(ID3D11DeviceC static HRESULT STDMETHODCALLTYPE d3d11_device_context_FinishCommandList(ID3D11DeviceContext1 *iface, BOOL restore, ID3D11CommandList **command_list) { + struct d3d11_device_context *context = impl_from_ID3D11DeviceContext1(iface); + struct d3d11_command_list *object; + HRESULT hr; + TRACE("iface %p, restore %#x, command_list %p.\n", iface, restore, command_list);
- return DXGI_ERROR_INVALID_CALL; + if (context->type == D3D11_DEVICE_CONTEXT_IMMEDIATE) + { + WARN("Attempt to record command list on an immediate context; returning DXGI_ERROR_INVALID_CALL.\n"); + return DXGI_ERROR_INVALID_CALL; + } + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + wined3d_mutex_lock(); + + if (FAILED(hr = wined3d_deferred_context_record_command_list(context->wined3d_context, + !!restore, &object->wined3d_list))) + { + WARN("Failed to record wined3d command list, hr %#x.\n", hr); + heap_free(object); + return hr; + } + + wined3d_mutex_unlock(); + + object->ID3D11CommandList_iface.lpVtbl = &d3d11_command_list_vtbl; + object->refcount = 1; + object->device = &context->device->ID3D11Device2_iface; + wined3d_private_store_init(&object->private_store); + + ID3D11Device2_AddRef(object->device); + + TRACE("Created command list %p.\n", object); + *command_list = &object->ID3D11CommandList_iface; + + return S_OK; }
static void STDMETHODCALLTYPE d3d11_device_context_CopySubresourceRegion1(ID3D11DeviceContext1 *iface, diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index b55bfdab866..db1c811a1f1 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -26,6 +26,59 @@ WINE_DECLARE_DEBUG_CHANNEL(fps);
#define WINED3D_INITIAL_CS_SIZE 4096
+struct wined3d_command_list +{ + LONG refcount; + + struct wined3d_device *device; + + SIZE_T data_size; + void *data; + + SIZE_T resource_count; + struct wined3d_resource **resources; +}; + +static void wined3d_command_list_destroy_object(void *object) +{ + struct wined3d_command_list *list = object; + + TRACE("list %p.\n", list); + + heap_free(list->resources); + heap_free(list->data); + heap_free(list); +} + +ULONG CDECL wined3d_command_list_incref(struct wined3d_command_list *list) +{ + ULONG refcount = InterlockedIncrement(&list->refcount); + + TRACE("%p increasing refcount to %u.\n", list, refcount); + + return refcount; +} + +ULONG CDECL wined3d_command_list_decref(struct wined3d_command_list *list) +{ + ULONG refcount = InterlockedDecrement(&list->refcount); + struct wined3d_device *device = list->device; + + TRACE("%p decreasing refcount to %u.\n", list, refcount); + + if (!refcount) + { + SIZE_T i; + + for (i = 0; i < list->resource_count; ++i) + wined3d_resource_decref(list->resources[i]); + + wined3d_cs_destroy_object(device->cs, wined3d_command_list_destroy_object, list); + } + + return refcount; +} + enum wined3d_cs_op { WINED3D_CS_OP_NOP, @@ -3333,3 +3386,53 @@ void CDECL wined3d_deferred_context_destroy(struct wined3d_device_context *conte heap_free(deferred->data); heap_free(deferred); } + +HRESULT CDECL wined3d_deferred_context_record_command_list(struct wined3d_device_context *context, + bool restore, struct wined3d_command_list **list) +{ + struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context); + struct wined3d_command_list *object; + + TRACE("context %p, list %p.\n", context, list); + + if (restore) + { + FIXME("Restoring context state is not implemented.\n"); + return E_NOTIMPL; + } + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->refcount = 1; + object->device = deferred->c.device; + + if (!(object->data = heap_alloc(deferred->data_size))) + { + heap_free(object); + return E_OUTOFMEMORY; + } + object->data_size = deferred->data_size; + memcpy(object->data, deferred->data, deferred->data_size); + + if (!(object->resources = heap_alloc(deferred->resource_count * sizeof(*object->resources)))) + { + heap_free(object->data); + heap_free(object); + return E_OUTOFMEMORY; + } + object->resource_count = deferred->resource_count; + memcpy(object->resources, deferred->resources, deferred->resource_count * sizeof(*object->resources)); + /* Transfer our references to the resources to the command list. */ + + deferred->data_size = 0; + deferred->resource_count = 0; + + /* This is in fact recorded into a subsequent command list. */ + wined3d_device_context_reset_state(&deferred->c); + + TRACE("Created command list %p.\n", object); + *list = object; + + return S_OK; +} diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 84412515c39..6683b3bc30f 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -33,8 +33,12 @@ @ cdecl wined3d_buffer_get_resource(ptr) @ cdecl wined3d_buffer_incref(ptr)
+@ cdecl wined3d_command_list_decref(ptr) +@ cdecl wined3d_command_list_incref(ptr) + @ cdecl wined3d_deferred_context_create(ptr ptr) @ cdecl wined3d_deferred_context_destroy(ptr) +@ cdecl wined3d_deferred_context_record_command_list(ptr long ptr)
@ cdecl wined3d_depth_stencil_state_create(ptr ptr ptr ptr ptr) @ cdecl wined3d_depth_stencil_state_decref(ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index 812c042cdd7..bb6bf58a822 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2221,6 +2221,7 @@ struct wined3d; struct wined3d_adapter; struct wined3d_blend_state; struct wined3d_buffer; +struct wined3d_command_list; struct wined3d_depth_stencil_state; struct wined3d_device; struct wined3d_device_context; @@ -2340,8 +2341,13 @@ void * __cdecl wined3d_buffer_get_parent(const struct wined3d_buffer *buffer); struct wined3d_resource * __cdecl wined3d_buffer_get_resource(struct wined3d_buffer *buffer); ULONG __cdecl wined3d_buffer_incref(struct wined3d_buffer *buffer);
+ULONG __cdecl wined3d_command_list_decref(struct wined3d_command_list *list); +ULONG __cdecl wined3d_command_list_incref(struct wined3d_command_list *list); + HRESULT __cdecl wined3d_deferred_context_create(struct wined3d_device *device, struct wined3d_device_context **context); void __cdecl wined3d_deferred_context_destroy(struct wined3d_device_context *context); +HRESULT __cdecl wined3d_deferred_context_record_command_list(struct wined3d_device_context *context, + bool restore, struct wined3d_command_list **list);
HRESULT __cdecl wined3d_depth_stencil_state_create(struct wined3d_device *device, const struct wined3d_depth_stencil_state_desc *desc, void *parent,