[PATCH v2 1/5] d3d11: Add initial implementation of CreateDeviceContextState.

Rémi Bernon rbernon at codeweavers.com
Tue Jan 26 05:14:25 CST 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

v2: Fix the mess, d3d_device_context_state are free objects that simply
hold a reference to their device on creation and release it on destroy.

As suggested, this is the beginning of a series implementating D3D11
state capture and restore, to fix the D2D1 regression [1] by using D3D11
interfaces in D2D1 instead of D3D10.

[1] https://bugs.winehq.org/show_bug.cgi?id=49395

Activating D3D10 interface should actually disable most of the D3D11
interface methods, and the other way respectively. This is currently
left implemented, as it's not really required for the purpose of the
series.

 dlls/d3d11/d3d11_private.h |  12 ++++
 dlls/d3d11/device.c        | 142 ++++++++++++++++++++++++++++++++++++-
 dlls/d3d11/tests/d3d11.c   |  74 +++++++++++++------
 3 files changed, 206 insertions(+), 22 deletions(-)

diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h
index 3248285fcda..77078a07545 100644
--- a/dlls/d3d11/d3d11_private.h
+++ b/dlls/d3d11/d3d11_private.h
@@ -516,6 +516,18 @@ struct d3d_query *unsafe_impl_from_ID3D11Query(ID3D11Query *iface) DECLSPEC_HIDD
 struct d3d_query *unsafe_impl_from_ID3D10Query(ID3D10Query *iface) DECLSPEC_HIDDEN;
 struct d3d_query *unsafe_impl_from_ID3D11Asynchronous(ID3D11Asynchronous *iface) DECLSPEC_HIDDEN;
 
+/* ID3DDeviceContextState */
+struct d3d_device_context_state
+{
+    ID3DDeviceContextState ID3DDeviceContextState_iface;
+    LONG refcount;
+
+    struct wined3d_private_store private_store;
+
+    GUID emulated_interface;
+    ID3D11Device2 *device;
+};
+
 /* ID3D11DeviceContext - immediate context */
 struct d3d11_immediate_context
 {
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index 50e8cd58fe2..e870399a83e 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -29,6 +29,127 @@ static const struct wined3d_parent_ops d3d_null_wined3d_parent_ops =
     d3d_null_wined3d_object_destroyed,
 };
 
+/* ID3DDeviceContextState methods */
+
+static inline struct d3d_device_context_state *impl_from_ID3DDeviceContextState(ID3DDeviceContextState *iface)
+{
+    return CONTAINING_RECORD(iface, struct d3d_device_context_state, ID3DDeviceContextState_iface);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d_device_context_state_QueryInterface(ID3DDeviceContextState *iface,
+        REFIID iid, void **out)
+{
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_ID3DDeviceContextState)
+            || IsEqualGUID(iid, &IID_ID3D11DeviceChild)
+            || IsEqualGUID(iid, &IID_IUnknown))
+    {
+        ID3DDeviceContextState_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 d3d_device_context_state_AddRef(ID3DDeviceContextState *iface)
+{
+    struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface);
+    ULONG refcount = InterlockedIncrement(&state->refcount);
+
+    TRACE("%p increasing refcount to %u.\n", state, refcount);
+
+    return refcount;
+}
+
+static ULONG STDMETHODCALLTYPE d3d_device_context_state_Release(ID3DDeviceContextState *iface)
+{
+    struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface);
+    ULONG refcount = InterlockedDecrement(&state->refcount);
+
+    TRACE("%p decreasing refcount to %u.\n", state, refcount);
+
+    if (!refcount)
+    {
+        wined3d_private_store_cleanup(&state->private_store);
+        ID3D11Device2_Release(state->device);
+        heap_free(state);
+    }
+
+    return refcount;
+}
+
+static void STDMETHODCALLTYPE d3d_device_context_state_GetDevice(ID3DDeviceContextState *iface, ID3D11Device **device)
+{
+    struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface);
+
+    TRACE("iface %p, device %p.\n", iface, device);
+
+    *device = (ID3D11Device *)state->device;
+    ID3D11Device_AddRef(*device);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d_device_context_state_GetPrivateData(ID3DDeviceContextState *iface, REFGUID guid,
+        UINT *data_size, void *data)
+{
+    struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface);
+
+    TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return d3d_get_private_data(&state->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d_device_context_state_SetPrivateData(ID3DDeviceContextState *iface, REFGUID guid,
+        UINT data_size, const void *data)
+{
+    struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface);
+
+    TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
+
+    return d3d_set_private_data(&state->private_store, guid, data_size, data);
+}
+
+static HRESULT STDMETHODCALLTYPE d3d_device_context_state_SetPrivateDataInterface(ID3DDeviceContextState *iface,
+        REFGUID guid, const IUnknown *data)
+{
+    struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface);
+
+    TRACE("iface %p, guid %s, data %p.\n", iface, debugstr_guid(guid), data);
+
+    return d3d_set_private_data_interface(&state->private_store, guid, data);
+}
+
+static const struct ID3DDeviceContextStateVtbl d3d_device_context_state_vtbl =
+{
+    /* IUnknown methods */
+    d3d_device_context_state_QueryInterface,
+    d3d_device_context_state_AddRef,
+    d3d_device_context_state_Release,
+    /* ID3D11DeviceChild methods */
+    d3d_device_context_state_GetDevice,
+    d3d_device_context_state_GetPrivateData,
+    d3d_device_context_state_SetPrivateData,
+    d3d_device_context_state_SetPrivateDataInterface,
+    /* ID3DDeviceContextState methods */
+};
+
+static void d3d_device_context_state_init(struct d3d_device_context_state *state, struct d3d_device *device,
+        REFIID emulated_interface)
+{
+    state->ID3DDeviceContextState_iface.lpVtbl = &d3d_device_context_state_vtbl;
+    state->refcount = 1;
+
+    wined3d_private_store_init(&state->private_store);
+
+    state->emulated_interface = *emulated_interface;
+    state->device = &device->ID3D11Device2_iface;
+    ID3D11Device2_AddRef(state->device);
+}
+
 /* ID3D11DeviceContext - immediate context methods */
 
 static inline struct d3d11_immediate_context *impl_from_ID3D11DeviceContext1(ID3D11DeviceContext1 *iface)
@@ -3738,11 +3859,28 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateDeviceContextState(ID3D11Dev
         const D3D_FEATURE_LEVEL *feature_levels, UINT feature_levels_count, UINT sdk_version,
         REFIID emulated_interface, D3D_FEATURE_LEVEL *chosen_feature_level, ID3DDeviceContextState **state)
 {
+    struct d3d_device *device = impl_from_ID3D11Device2(iface);
+    struct d3d_device_context_state *state_impl;
+
     FIXME("iface %p, flags %#x, feature_levels %p, feature_level_count %u, sdk_version %u, "
-            "emulated_interface %s, chosen_feature_level %p, state %p stub!\n", iface, flags, feature_levels,
+            "emulated_interface %s, chosen_feature_level %p, state %p semi-stub!\n", iface, flags, feature_levels,
             feature_levels_count, sdk_version, debugstr_guid(emulated_interface), chosen_feature_level, state);
 
-    return E_NOTIMPL;
+    if (chosen_feature_level)
+       FIXME("Device context state feature level not implemented yet.\n");
+
+    if (state)
+    {
+        *state = NULL;
+        if (!(state_impl = heap_alloc(sizeof(*state_impl))))
+            return E_OUTOFMEMORY;
+        d3d_device_context_state_init(state_impl, device, emulated_interface);
+        *state = &state_impl->ID3DDeviceContextState_iface;
+    }
+
+    device->d3d11_only = FALSE;
+    if (chosen_feature_level) *chosen_feature_level = ID3D11Device2_GetFeatureLevel(iface);
+    return state ? S_OK : S_FALSE;
 }
 
 static HRESULT STDMETHODCALLTYPE d3d11_device_OpenSharedResource1(ID3D11Device2 *iface, HANDLE handle,
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 9fc09a5ec83..fde7a11766d 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -6683,10 +6683,9 @@ static void test_device_context_state(void)
     ok(tmp_sampler == sampler, "Got sampler %p, expected %p.\n", tmp_sampler, sampler);
     ID3D11SamplerState_Release(tmp_sampler);
 
-    feature_level = min(feature_level, D3D_FEATURE_LEVEL_10_1);
+    feature_level = min(feature_level, D3D_FEATURE_LEVEL_11_1);
     hr = ID3D11Device1_CreateDeviceContextState(device, 0, &feature_level, 1, D3D11_SDK_VERSION,
-            &IID_ID3D10Device, NULL, &context_state);
-todo_wine
+            &IID_ID3D11Device1, NULL, &context_state);
     ok(SUCCEEDED(hr), "Failed to create device context state, hr %#x.\n", hr);
     if (FAILED(hr))
     {
@@ -6700,6 +6699,24 @@ todo_wine
     context_type = ID3D11DeviceContext1_GetType(context);
     ok(context_type == D3D11_DEVICE_CONTEXT_IMMEDIATE, "Unexpected context type %u.\n", context_type);
 
+    check_interface(device, &IID_ID3D10Device, TRUE, FALSE);
+    check_interface(device, &IID_ID3D10Device1, TRUE, FALSE);
+    check_interface(device, &IID_ID3D11Device, TRUE, FALSE);
+    check_interface(device, &IID_ID3D11Device1, TRUE, FALSE);
+
+    refcount = ID3DDeviceContextState_Release(context_state);
+    ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
+
+    feature_level = min(feature_level, D3D_FEATURE_LEVEL_10_1);
+    hr = ID3D11Device1_CreateDeviceContextState(device, 0, &feature_level, 1, D3D11_SDK_VERSION,
+            &IID_ID3D10Device, NULL, &context_state);
+    ok(SUCCEEDED(hr), "Failed to create device context state, hr %#x.\n", hr);
+    refcount = get_refcount(context_state);
+    ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
+
+    context_type = ID3D11DeviceContext1_GetType(context);
+    ok(context_type == D3D11_DEVICE_CONTEXT_IMMEDIATE, "Unexpected context type %u.\n", context_type);
+
     cb = create_buffer((ID3D11Device *)device, D3D11_BIND_CONSTANT_BUFFER, sizeof(constant), NULL);
 
     ID3D11DeviceContext1_CSSetConstantBuffers(context, 0, 1, &cb);
@@ -6743,73 +6760,90 @@ todo_wine
     ID3D11DeviceContext1_SwapDeviceContextState(context, context_state, &previous_context_state);
     refcount = ID3DDeviceContextState_Release(context_state);
     ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
+    todo_wine ok(previous_context_state != NULL, "Failed to get previous context state\n");
+
+    context_type = ID3D11DeviceContext1_GetType(context);
+    ok(context_type == D3D11_DEVICE_CONTEXT_IMMEDIATE, "Unexpected context type %u.\n", context_type);
 
     ID3D11DeviceContext1_PSSetSamplers(context, 0, 1, &sampler);
     tmp_sampler = (ID3D11SamplerState *)0xdeadbeef;
     ID3D11DeviceContext1_PSGetSamplers(context, 0, 1, &tmp_sampler);
-    ok(tmp_sampler == (ID3D11SamplerState *)0xdeadbeef, "Got unexpected sampler %p.\n", tmp_sampler);
+    todo_wine ok(tmp_sampler == (ID3D11SamplerState *)0xdeadbeef, "Got unexpected sampler %p.\n", tmp_sampler);
+    if (tmp_sampler && tmp_sampler != (ID3D11SamplerState *)0xdeadbeef)
+        ID3D11SamplerState_Release(tmp_sampler);
     if (!enable_debug_layer)
         ID3D11DeviceContext1_PSSetSamplers(context, 0, 1, &tmp_sampler);
 
     ID3D11DeviceContext1_CSSetSamplers(context, 0, 1, &sampler);
     tmp_sampler = (ID3D11SamplerState *)0xdeadbeef;
     ID3D11DeviceContext1_CSGetSamplers(context, 0, 1, &tmp_sampler);
-    ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    todo_wine ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    if (tmp_sampler) ID3D11SamplerState_Release(tmp_sampler);
 
     ID3D11DeviceContext1_DSSetSamplers(context, 0, 1, &sampler);
     tmp_sampler = (ID3D11SamplerState *)0xdeadbeef;
     ID3D11DeviceContext1_DSGetSamplers(context, 0, 1, &tmp_sampler);
-    ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    todo_wine ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    if (tmp_sampler) ID3D11SamplerState_Release(tmp_sampler);
 
     ID3D11DeviceContext1_GSSetSamplers(context, 0, 1, &sampler);
     tmp_sampler = (ID3D11SamplerState *)0xdeadbeef;
     ID3D11DeviceContext1_GSGetSamplers(context, 0, 1, &tmp_sampler);
-    ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    todo_wine ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    if (tmp_sampler) ID3D11SamplerState_Release(tmp_sampler);
 
     ID3D11DeviceContext1_HSSetSamplers(context, 0, 1, &sampler);
     tmp_sampler = (ID3D11SamplerState *)0xdeadbeef;
     ID3D11DeviceContext1_HSGetSamplers(context, 0, 1, &tmp_sampler);
-    ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    todo_wine ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    if (tmp_sampler) ID3D11SamplerState_Release(tmp_sampler);
 
     ID3D11DeviceContext1_VSSetSamplers(context, 0, 1, &sampler);
     tmp_sampler = (ID3D11SamplerState *)0xdeadbeef;
     ID3D11DeviceContext1_VSGetSamplers(context, 0, 1, &tmp_sampler);
-    ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
-
-    context_type = ID3D11DeviceContext1_GetType(context);
-    ok(context_type == D3D11_DEVICE_CONTEXT_IMMEDIATE, "Unexpected context type %u.\n", context_type);
+    todo_wine ok(!tmp_sampler, "Got unexpected sampler %p.\n", tmp_sampler);
+    if (tmp_sampler) ID3D11SamplerState_Release(tmp_sampler);
 
     tmp_cb = (ID3D11Buffer *)0xdeadbeef;
     ID3D11DeviceContext1_CSGetConstantBuffers(context, 0, 1, &tmp_cb);
-    ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    todo_wine ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    if (tmp_cb) ID3D11Buffer_Release(tmp_cb);
 
     tmp_cb = (ID3D11Buffer *)0xdeadbeef;
     ID3D11DeviceContext1_PSGetConstantBuffers(context, 0, 1, &tmp_cb);
-    ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    todo_wine ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    if (tmp_cb) ID3D11Buffer_Release(tmp_cb);
 
     tmp_cb = (ID3D11Buffer *)0xdeadbeef;
     ID3D11DeviceContext1_VSGetConstantBuffers(context, 0, 1, &tmp_cb);
-    ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    todo_wine ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    if (tmp_cb) ID3D11Buffer_Release(tmp_cb);
 
     tmp_cb = (ID3D11Buffer *)0xdeadbeef;
     ID3D11DeviceContext1_DSGetConstantBuffers(context, 0, 1, &tmp_cb);
-    ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    todo_wine ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    if (tmp_cb) ID3D11Buffer_Release(tmp_cb);
 
     tmp_cb = (ID3D11Buffer *)0xdeadbeef;
     ID3D11DeviceContext1_GSGetConstantBuffers(context, 0, 1, &tmp_cb);
-    ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    todo_wine ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    if (tmp_cb) ID3D11Buffer_Release(tmp_cb);
 
     tmp_cb = (ID3D11Buffer *)0xdeadbeef;
     ID3D11DeviceContext1_HSGetConstantBuffers(context, 0, 1, &tmp_cb);
-    ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    todo_wine ok(!tmp_cb, "Got unexpected buffer %p.\n", tmp_cb);
+    if (tmp_cb) ID3D11Buffer_Release(tmp_cb);
 
     check_interface(device, &IID_ID3D10Device, TRUE, FALSE);
     check_interface(device, &IID_ID3D10Device1, TRUE, FALSE);
 
+    context_state = NULL;
     ID3D11DeviceContext1_SwapDeviceContextState(context, previous_context_state, &context_state);
-    refcount = ID3DDeviceContextState_Release(context_state);
+    if (!context_state) refcount = 0;
+    else refcount = ID3DDeviceContextState_Release(context_state);
     ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
-    refcount = ID3DDeviceContextState_Release(previous_context_state);
+    if (!previous_context_state) refcount = 0;
+    else refcount = ID3DDeviceContextState_Release(previous_context_state);
     ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
 
     /* ID3DDeviceContextState retains the previous state. */
-- 
2.30.0




More information about the wine-devel mailing list