[PATCH 2/8] d3d11: Implement ID3D11Device::CreateDeferredContext().

Zebediah Figura z.figura12 at gmail.com
Wed May 26 00:22:52 CDT 2021


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42191
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/d3d11/d3d11_private.h |   1 +
 dlls/d3d11/device.c        |  70 +++++++++++++++---
 dlls/d3d11/tests/d3d11.c   |  65 ++++++++--------
 dlls/wined3d/cs.c          | 147 +++++++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d.spec  |   3 +
 include/wine/wined3d.h     |   3 +
 6 files changed, 250 insertions(+), 39 deletions(-)

diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h
index 1a8cdc6d77c..2b5a51afbd1 100644
--- a/dlls/d3d11/d3d11_private.h
+++ b/dlls/d3d11/d3d11_private.h
@@ -547,6 +547,7 @@ struct d3d11_device_context
     ID3D11Multithread ID3D11Multithread_iface;
     LONG refcount;
 
+    D3D11_DEVICE_CONTEXT_TYPE type;
     struct wined3d_device_context *wined3d_context;
     struct d3d_device *device;
 
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index 2a012fce144..459c49145cd 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -351,7 +351,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_context_QueryInterface(ID3D11Devic
     {
         *out = &context->ID3D11DeviceContext1_iface;
     }
-    else if (IsEqualGUID(iid, &IID_ID3D11Multithread))
+    else if (context->type == D3D11_DEVICE_CONTEXT_IMMEDIATE && IsEqualGUID(iid, &IID_ID3D11Multithread))
     {
         *out = &context->ID3D11Multithread_iface;
     }
@@ -390,6 +390,11 @@ static ULONG STDMETHODCALLTYPE d3d11_device_context_Release(ID3D11DeviceContext1
 
     if (!refcount)
     {
+        if (context->type != D3D11_DEVICE_CONTEXT_IMMEDIATE)
+        {
+            wined3d_deferred_context_destroy(context->wined3d_context);
+            heap_free(context);
+        }
         ID3D11Device2_Release(&context->device->ID3D11Device2_iface);
     }
 
@@ -2645,9 +2650,11 @@ static void STDMETHODCALLTYPE d3d11_device_context_Flush(ID3D11DeviceContext1 *i
 
 static D3D11_DEVICE_CONTEXT_TYPE STDMETHODCALLTYPE d3d11_device_context_GetType(ID3D11DeviceContext1 *iface)
 {
+    struct d3d11_device_context *context = impl_from_ID3D11DeviceContext1(iface);
+
     TRACE("iface %p.\n", iface);
 
-    return D3D11_DEVICE_CONTEXT_IMMEDIATE;
+    return context->type;
 }
 
 static UINT STDMETHODCALLTYPE d3d11_device_context_GetContextFlags(ID3D11DeviceContext1 *iface)
@@ -2826,13 +2833,18 @@ static void STDMETHODCALLTYPE d3d11_device_context_SwapDeviceContextState(ID3D11
 
     TRACE("iface %p, state %p, prev %p.\n", iface, state, prev);
 
-    if (!state)
+    if (prev)
+        *prev = NULL;
+
+    if (context->type != D3D11_DEVICE_CONTEXT_IMMEDIATE)
     {
-        if (prev)
-            *prev = NULL;
+        WARN("SwapDeviceContextState is not allowed on a deferred context.\n");
         return;
     }
 
+    if (!state)
+        return;
+
     wined3d_mutex_lock();
 
     prev_impl = device->state;
@@ -3082,11 +3094,13 @@ static const struct ID3D11MultithreadVtbl d3d11_multithread_vtbl =
     d3d11_multithread_GetMultithreadProtected,
 };
 
-static void d3d11_device_context_init(struct d3d11_device_context *context, struct d3d_device *device)
+static void d3d11_device_context_init(struct d3d11_device_context *context, struct d3d_device *device,
+        D3D11_DEVICE_CONTEXT_TYPE type)
 {
     context->ID3D11DeviceContext1_iface.lpVtbl = &d3d11_device_context_vtbl;
     context->ID3D11Multithread_iface.lpVtbl = &d3d11_multithread_vtbl;
     context->refcount = 1;
+    context->type = type;
 
     context->device = device;
     ID3D11Device2_AddRef(&device->ID3D11Device2_iface);
@@ -3575,13 +3589,49 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateCounter(ID3D11Device2 *iface
     return E_NOTIMPL;
 }
 
+static HRESULT d3d11_deferred_context_create(struct d3d_device *device,
+        UINT flags, struct d3d11_device_context **context)
+{
+    struct d3d11_device_context *object;
+    HRESULT hr;
+
+    if (flags)
+        FIXME("Ignoring flags %#x.\n", flags);
+
+    if (!(object = heap_alloc_zero(sizeof(*object))))
+        return E_OUTOFMEMORY;
+    d3d11_device_context_init(object, device, D3D11_DEVICE_CONTEXT_DEFERRED);
+
+    wined3d_mutex_lock();
+    if (FAILED(hr = wined3d_deferred_context_create(device->wined3d_device, &object->wined3d_context)))
+    {
+        WARN("Failed to create wined3d deferred context, hr %#x.\n", hr);
+        heap_free(object);
+        wined3d_mutex_unlock();
+        return hr;
+    }
+    wined3d_mutex_unlock();
+
+    TRACE("Created deferred context %p.\n", object);
+    *context = object;
+
+    return S_OK;
+}
+
 static HRESULT STDMETHODCALLTYPE d3d11_device_CreateDeferredContext(ID3D11Device2 *iface, UINT flags,
         ID3D11DeviceContext **context)
 {
-    FIXME("iface %p, flags %#x, context %p stub!\n", iface, flags, context);
+    struct d3d_device *device = impl_from_ID3D11Device2(iface);
+    struct d3d11_device_context *object;
+    HRESULT hr;
 
-    *context = NULL;
-    return E_NOTIMPL;
+    TRACE("iface %p, flags %#x, context %p.\n", iface, flags, context);
+
+    if (FAILED(hr = d3d11_deferred_context_create(device, flags, &object)))
+        return hr;
+
+    *context = (ID3D11DeviceContext *)&object->ID3D11DeviceContext1_iface;
+    return S_OK;
 }
 
 static HRESULT STDMETHODCALLTYPE d3d11_device_OpenSharedResource(ID3D11Device2 *iface, HANDLE resource, REFIID iid,
@@ -6655,7 +6705,7 @@ void d3d_device_init(struct d3d_device *device, void *outer_unknown)
     device->d3d11_only = FALSE;
     device->state = NULL;
 
-    d3d11_device_context_init(&device->immediate_context, device);
+    d3d11_device_context_init(&device->immediate_context, device, D3D11_DEVICE_CONTEXT_IMMEDIATE);
     ID3D11DeviceContext1_Release(&device->immediate_context.ID3D11DeviceContext1_iface);
 
     wine_rb_init(&device->blend_states, d3d_blend_state_compare);
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 089755fd1ba..f415cbaad45 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -2266,6 +2266,8 @@ static void test_create_deferred_context(void)
 
     hr = ID3D11Device_CreateDeferredContext(device, 0, &context);
     todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Failed to create deferred context, hr %#x.\n", hr);
+    if (hr == S_OK)
+        ID3D11DeviceContext_Release(context);
 
     refcount = ID3D11Device_Release(device);
     ok(!refcount, "Device has %u references left.\n", refcount);
@@ -2278,9 +2280,7 @@ static void test_create_deferred_context(void)
 
     expected_refcount = get_refcount(device) + 1;
     hr = ID3D11Device_CreateDeferredContext(device, 0, &context);
-    todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
-    if (FAILED(hr))
-        goto done;
+    ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
     refcount = get_refcount(device);
     ok(refcount == expected_refcount, "Got refcount %u, expected %u.\n", refcount, expected_refcount);
     refcount = get_refcount(context);
@@ -2294,7 +2294,6 @@ static void test_create_deferred_context(void)
     refcount = ID3D11DeviceContext_Release(context);
     ok(!refcount, "Got unexpected refcount %u.\n", refcount);
 
-done:
     refcount = ID3D11Device_Release(device);
     ok(!refcount, "Device has %u references left.\n", refcount);
 }
@@ -32270,14 +32269,7 @@ static void test_deferred_context_state(void)
     ID3D11DeviceContext_PSSetConstantBuffers(immediate, 0, 1, &green_buffer);
 
     hr = ID3D11Device_CreateDeferredContext(device, 0, &deferred);
-    todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
-    if (hr != S_OK)
-    {
-        ID3D11Buffer_Release(blue_buffer);
-        ID3D11Buffer_Release(green_buffer);
-        release_test_context(&test_context);
-        return;
-    }
+    ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
 
     ID3D11DeviceContext_PSGetConstantBuffers(deferred, 0, 1, &ret_buffer);
     ok(!ret_buffer, "Got unexpected buffer %p.\n", ret_buffer);
@@ -32289,7 +32281,15 @@ static void test_deferred_context_state(void)
     ID3D11Buffer_Release(ret_buffer);
 
     hr = ID3D11DeviceContext_FinishCommandList(deferred, TRUE, &list1);
-    ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
+    todo_wine ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
+    if (hr != S_OK)
+    {
+        ID3D11DeviceContext_Release(deferred);
+        ID3D11Buffer_Release(blue_buffer);
+        ID3D11Buffer_Release(green_buffer);
+        release_test_context(&test_context);
+        return;
+    }
 
     ID3D11DeviceContext_PSGetConstantBuffers(deferred, 0, 1, &ret_buffer);
     ok(ret_buffer == blue_buffer, "Got unexpected buffer %p.\n", ret_buffer);
@@ -32468,12 +32468,7 @@ static void test_deferred_context_rendering(void)
     immediate = test_context.immediate_context;
 
     hr = ID3D11Device_CreateDeferredContext(device, 0, &deferred);
-    todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
-    if (hr != S_OK)
-    {
-        release_test_context(&test_context);
-        return;
-    }
+    ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
 
     memset(&blend_desc, 0, sizeof(blend_desc));
 
@@ -32492,7 +32487,16 @@ static void test_deferred_context_rendering(void)
     ID3D11DeviceContext_ClearRenderTargetView(deferred, test_context.backbuffer_rtv, green);
 
     hr = ID3D11DeviceContext_FinishCommandList(deferred, TRUE, &list1);
-    ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
+    todo_wine ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
+    if (hr != S_OK)
+    {
+        ID3D11BlendState_Release(red_blend);
+        ID3D11BlendState_Release(green_blend);
+        ID3D11BlendState_Release(blue_blend);
+        ID3D11DeviceContext_Release(deferred);
+        release_test_context(&test_context);
+        return;
+    }
 
     hr = ID3D11DeviceContext_FinishCommandList(deferred, TRUE, &list2);
     ok(hr == S_OK, "Failed to create command list, hr %#x.\n", hr);
@@ -32729,12 +32733,7 @@ static void test_deferred_context_map(void)
     immediate = test_context.immediate_context;
 
     hr = ID3D11Device_CreateDeferredContext(device, 0, &deferred);
-    todo_wine ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
-    if (hr != S_OK)
-    {
-        release_test_context(&test_context);
-        return;
-    }
+    ok(hr == S_OK, "Failed to create deferred context, hr %#x.\n", hr);
 
     for (i = 0; i < ARRAY_SIZE(data); ++i)
         data[i] = i;
@@ -32758,13 +32757,21 @@ static void test_deferred_context_map(void)
     ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
 
     hr = ID3D11DeviceContext_Map(deferred, (ID3D11Resource *)buffer, 0, D3D11_MAP_WRITE, 0, &map_desc);
-    ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
+    todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr);
 
     hr = ID3D11DeviceContext_Map(deferred, (ID3D11Resource *)buffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &map_desc);
-    ok(hr == D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD, "Got unexpected hr %#x.\n", hr);
+    todo_wine ok(hr == D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD, "Got unexpected hr %#x.\n", hr);
 
     hr = ID3D11DeviceContext_Map(deferred, (ID3D11Resource *)buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map_desc);
-    ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+    if (hr != S_OK)
+    {
+        ID3D11Buffer_Release(buffer2);
+        ID3D11Buffer_Release(buffer);
+        ID3D11DeviceContext_Release(deferred);
+        release_test_context(&test_context);
+        return;
+    }
     map_data = map_desc.pData;
     /* The previous contents of map_data are undefined and may in practice be
      * uninitialized garbage. */
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 8702ac08631..9a143b915ed 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -3162,3 +3162,150 @@ void wined3d_cs_destroy(struct wined3d_cs *cs)
     heap_free(cs->data);
     heap_free(cs);
 }
+
+struct wined3d_deferred_context
+{
+    struct wined3d_device_context c;
+
+    SIZE_T data_size, data_capacity;
+    void *data;
+};
+
+static struct wined3d_deferred_context *wined3d_deferred_context_from_context(struct wined3d_device_context *context)
+{
+    return CONTAINING_RECORD(context, struct wined3d_deferred_context, c);
+}
+
+static void *wined3d_deferred_context_require_space(struct wined3d_device_context *context,
+        size_t size, enum wined3d_cs_queue_id queue_id)
+{
+    struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
+    struct wined3d_cs_packet *packet;
+    size_t header_size, packet_size;
+
+    assert(queue_id == WINED3D_CS_QUEUE_DEFAULT);
+
+    header_size = offsetof(struct wined3d_cs_packet, data[0]);
+    packet_size = offsetof(struct wined3d_cs_packet, data[size]);
+    packet_size = (packet_size + header_size - 1) & ~(header_size - 1);
+
+    if (!wined3d_array_reserve(&deferred->data, &deferred->data_capacity, deferred->data_size + packet_size, 1))
+        return NULL;
+
+    packet = (struct wined3d_cs_packet *)((BYTE *)deferred->data + deferred->data_size);
+    TRACE("size was %zu, adding %zu\n", (size_t)deferred->data_size, packet_size);
+    deferred->data_size += packet_size;
+    packet->size = packet_size - header_size;
+    return &packet->data;
+}
+
+static void wined3d_deferred_context_submit(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
+{
+    assert(queue_id == WINED3D_CS_QUEUE_DEFAULT);
+
+    /* Nothing to do. */
+}
+
+static void wined3d_deferred_context_finish(struct wined3d_device_context *context, enum wined3d_cs_queue_id queue_id)
+{
+    /* This should not happen; we cannot meaningfully finish a deferred context. */
+    ERR("Ignoring finish() on a deferred context.\n");
+}
+
+static void wined3d_deferred_context_push_constants(struct wined3d_device_context *context,
+        enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants)
+{
+    FIXME("context %p, p %#x, start_idx %u, count %u, constants %p, stub!\n", context, p, start_idx, count, constants);
+}
+
+static HRESULT wined3d_deferred_context_map(struct wined3d_device_context *context,
+        struct wined3d_resource *resource, unsigned int sub_resource_idx,
+        struct wined3d_map_desc *map_desc, const struct wined3d_box *box, unsigned int flags)
+{
+    FIXME("context %p, resource %p, sub_resource_idx %u, map_desc %p, box %p, flags %#x, stub!\n",
+            context, resource, sub_resource_idx, map_desc, box, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT wined3d_deferred_context_unmap(struct wined3d_device_context *context,
+        struct wined3d_resource *resource, unsigned int sub_resource_idx)
+{
+    FIXME("context %p, resource %p, sub_resource_idx %u, stub!\n",
+            context, resource, sub_resource_idx);
+    return E_NOTIMPL;
+}
+
+static void wined3d_deferred_context_update_sub_resource(struct wined3d_device_context *context,
+        struct wined3d_resource *resource, unsigned int sub_resource_idx, const struct wined3d_box *box,
+        const void *data, unsigned int row_pitch, unsigned int slice_pitch)
+{
+    FIXME("context %p, resource %p, sub_resource_idx %u, box %p, data %p, row_pitch %u, slice_pitch %u, stub!\n",
+            context, resource, sub_resource_idx, box, data, row_pitch, slice_pitch);
+}
+
+static void wined3d_deferred_context_issue_query(struct wined3d_device_context *context,
+        struct wined3d_query *query, unsigned int flags)
+{
+    FIXME("context %p, query %p, flags %#x, stub!\n", context, query, flags);
+}
+
+static void wined3d_deferred_context_flush(struct wined3d_device_context *context)
+{
+    FIXME("context %p, stub!\n", context);
+}
+
+static void wined3d_deferred_context_acquire_resource(struct wined3d_device_context *context,
+        struct wined3d_resource *resource)
+{
+    FIXME("context %p, resource %p, stub!\n", context, resource);
+}
+
+static const struct wined3d_device_context_ops wined3d_deferred_context_ops =
+{
+    wined3d_deferred_context_require_space,
+    wined3d_deferred_context_submit,
+    wined3d_deferred_context_finish,
+    wined3d_deferred_context_push_constants,
+    wined3d_deferred_context_map,
+    wined3d_deferred_context_unmap,
+    wined3d_deferred_context_update_sub_resource,
+    wined3d_deferred_context_issue_query,
+    wined3d_deferred_context_flush,
+    wined3d_deferred_context_acquire_resource,
+};
+
+HRESULT CDECL wined3d_deferred_context_create(struct wined3d_device *device, struct wined3d_device_context **context)
+{
+    struct wined3d_deferred_context *object;
+    HRESULT hr;
+
+    TRACE("device %p, context %p.\n", device, context);
+
+    if (!(object = heap_alloc_zero(sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    if (FAILED(hr = wined3d_state_create(device, &device->cs->c.state->feature_level, 1, &object->c.state)))
+    {
+        heap_free(object);
+        return hr;
+    }
+
+    object->c.ops = &wined3d_deferred_context_ops;
+    object->c.device = device;
+
+    TRACE("Created deferred context %p.\n", context);
+    *context = &object->c;
+
+    return S_OK;
+}
+
+void CDECL wined3d_deferred_context_destroy(struct wined3d_device_context *context)
+{
+    struct wined3d_deferred_context *deferred = wined3d_deferred_context_from_context(context);
+
+    TRACE("context %p.\n", context);
+
+    wined3d_state_destroy(deferred->c.state);
+    heap_free(deferred->data);
+    heap_free(deferred);
+}
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 9f3dfed7ef8..901e9bee621 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -33,6 +33,9 @@
 @ cdecl wined3d_buffer_get_resource(ptr)
 @ cdecl wined3d_buffer_incref(ptr)
 
+@ cdecl wined3d_deferred_context_create(ptr ptr)
+@ cdecl wined3d_deferred_context_destroy(ptr)
+
 @ cdecl wined3d_depth_stencil_state_create(ptr ptr ptr ptr ptr)
 @ cdecl wined3d_depth_stencil_state_decref(ptr)
 @ cdecl wined3d_depth_stencil_state_get_parent(ptr)
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 2ee18bcaaed..0be192b0f01 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2340,6 +2340,9 @@ 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);
 
+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_depth_stencil_state_create(struct wined3d_device *device,
         const struct wined3d_depth_stencil_state_desc *desc, void *parent,
         const struct wined3d_parent_ops *parent_ops, struct wined3d_depth_stencil_state **state);
-- 
2.30.2




More information about the wine-devel mailing list