Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
These two patches should be mostly independent from the rest of the d3d11 state swap implementation, so I'm sending them now.
In the first patch, I'm not making any change to the rest of the logic, although some ifs are now redundant with the initial checks, because the function will have to be completely rewritten later anyway.
dlls/d3d11/device.c | 3 +++ dlls/d3d11/tests/d3d11.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 8e5beb8893b..914b64d6019 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -2761,6 +2761,9 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_SwapDeviceContextState(ID3
FIXME("iface %p, state %p, prev_state %p semi-stub!\n", iface, state, prev_state);
+ if (prev_state) *prev_state = NULL; + if (!state) return; + wined3d_mutex_lock(); if (prev_state) { diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c index 044c1ce5a17..1505b3fddbc 100644 --- a/dlls/d3d11/tests/d3d11.c +++ b/dlls/d3d11/tests/d3d11.c @@ -7078,8 +7078,7 @@ static void test_device_context_state(void)
previous_context_state = (ID3DDeviceContextState *)0xdeadbeef; ID3D11DeviceContext1_SwapDeviceContextState(context, NULL, &previous_context_state); - todo_wine ok(previous_context_state == NULL, "Got unexpected state pointer.\n"); - if (previous_context_state) ID3DDeviceContextState_Release(previous_context_state); + ok(previous_context_state == NULL, "Got unexpected state pointer.\n"); previous_context_state = NULL; ID3D11DeviceContext1_SwapDeviceContextState(context, context_state, &previous_context_state); ok(previous_context_state != NULL, "Failed to get previous context state\n");
And use its emulated_interface. This adds a private_refcount to track hidden references, and a reference to the wined3d_device, to keep the d3d_device alive while not publicly referencing it.
This uses d3d_device_context_state_AddRef on init so that the initial references are also traced, making it easier to verify that nothing is leaked.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/d3d11/d3d11_main.c | 1 - dlls/d3d11/d3d11_private.h | 6 ++-- dlls/d3d11/device.c | 69 +++++++++++++++++++++++++++++++------- 3 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/dlls/d3d11/d3d11_main.c b/dlls/d3d11/d3d11_main.c index 6666876049d..dac59d09999 100644 --- a/dlls/d3d11/d3d11_main.c +++ b/dlls/d3d11/d3d11_main.c @@ -137,7 +137,6 @@ HRESULT WINAPI D3D11CoreCreateDevice(IDXGIFactory *factory, IDXGIAdapter *adapte return E_FAIL; } d3d_device->d3d11_only = TRUE; - d3d_device->emulated_interface = IID_ID3D11Device2;
return S_OK; } diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h index cdae1104efa..650b5c35871 100644 --- a/dlls/d3d11/d3d11_private.h +++ b/dlls/d3d11/d3d11_private.h @@ -520,7 +520,7 @@ struct d3d_query *unsafe_impl_from_ID3D11Asynchronous(ID3D11Asynchronous *iface) struct d3d_device_context_state { ID3DDeviceContextState ID3DDeviceContextState_iface; - LONG refcount; + LONG refcount, private_refcount;
struct wined3d_private_store private_store; struct @@ -546,6 +546,8 @@ struct d3d_device_context_state } ps;
GUID emulated_interface; + + struct wined3d_device *wined3d_device; ID3D11Device2 *device; };
@@ -572,8 +574,8 @@ struct d3d_device
D3D_FEATURE_LEVEL feature_level; BOOL d3d11_only; - GUID emulated_interface;
+ struct d3d_device_context_state *state; struct d3d11_immediate_context immediate_context;
struct wined3d_device_parent device_parent; diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c index 914b64d6019..87bdd594d81 100644 --- a/dlls/d3d11/device.c +++ b/dlls/d3d11/device.c @@ -31,8 +31,9 @@ static const struct wined3d_parent_ops d3d_null_wined3d_parent_ops =
static inline BOOL d3d_device_is_d3d10_active(struct d3d_device *device) { - return IsEqualGUID(&device->emulated_interface, &IID_ID3D10Device) - || IsEqualGUID(&device->emulated_interface, &IID_ID3D10Device1); + return !device->state + || IsEqualGUID(&device->state->emulated_interface, &IID_ID3D10Device) + || IsEqualGUID(&device->state->emulated_interface, &IID_ID3D10Device1); }
/* ID3DDeviceContextState methods */ @@ -62,6 +63,15 @@ static HRESULT STDMETHODCALLTYPE d3d_device_context_state_QueryInterface(ID3DDev return E_NOINTERFACE; }
+static ULONG d3d_device_context_state_private_addref(struct d3d_device_context_state *state) +{ + ULONG refcount = InterlockedIncrement(&state->private_refcount); + + TRACE("%p increasing private refcount to %u.\n", state, refcount); + + return refcount; +} + static ULONG STDMETHODCALLTYPE d3d_device_context_state_AddRef(ID3DDeviceContextState *iface) { struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface); @@ -69,16 +79,21 @@ static ULONG STDMETHODCALLTYPE d3d_device_context_state_AddRef(ID3DDeviceContext
TRACE("%p increasing refcount to %u.\n", state, refcount);
+ if (refcount == 1) + { + d3d_device_context_state_private_addref(state); + ID3D11Device2_AddRef(state->device); + } + return refcount; }
-static ULONG STDMETHODCALLTYPE d3d_device_context_state_Release(ID3DDeviceContextState *iface) +static void d3d_device_context_state_private_release(struct d3d_device_context_state *state) { - struct d3d_device_context_state *state = impl_from_ID3DDeviceContextState(iface); - ULONG refcount = InterlockedDecrement(&state->refcount); + ULONG refcount = InterlockedDecrement(&state->private_refcount); unsigned int i;
- TRACE("%p decreasing refcount to %u.\n", state, refcount); + TRACE("%p decreasing private refcount to %u.\n", state, refcount);
if (!refcount) { @@ -104,9 +119,23 @@ static ULONG STDMETHODCALLTYPE d3d_device_context_state_Release(ID3DDeviceContex if (state->gs.cbs[i]) ID3D11Buffer_Release(state->gs.cbs[i]); if (state->ps.cbs[i]) ID3D11Buffer_Release(state->ps.cbs[i]); } - ID3D11Device2_Release(state->device); + wined3d_device_decref(state->wined3d_device); heap_free(state); } +} + +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) + { + ID3D11Device2_Release(state->device); + d3d_device_context_state_private_release(state); + }
return refcount; } @@ -169,7 +198,7 @@ static void d3d_device_context_state_init(struct d3d_device_context_state *state REFIID emulated_interface) { state->ID3DDeviceContextState_iface.lpVtbl = &d3d_device_context_state_vtbl; - state->refcount = 1; + state->refcount = state->private_refcount = 0;
wined3d_private_store_init(&state->private_store); memset(&state->vs, 0, sizeof(state->vs)); @@ -177,8 +206,10 @@ static void d3d_device_context_state_init(struct d3d_device_context_state *state memset(&state->ps, 0, sizeof(state->ps));
state->emulated_interface = *emulated_interface; + wined3d_device_incref(state->wined3d_device = device->wined3d_device); state->device = &device->ID3D11Device2_iface; - ID3D11Device2_AddRef(state->device); + + d3d_device_context_state_AddRef(&state->ID3DDeviceContextState_iface); }
/* ID3D11DeviceContext - immediate context methods */ @@ -2770,7 +2801,7 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_SwapDeviceContextState(ID3 *prev_state = NULL; if ((state_impl = heap_alloc(sizeof(*state_impl)))) { - d3d_device_context_state_init(state_impl, device, &device->emulated_interface); + d3d_device_context_state_init(state_impl, device, &device->state->emulated_interface); d3d11_immediate_context_capture_state(iface, state_impl); *prev_state = &state_impl->ID3DDeviceContextState_iface; } @@ -2779,7 +2810,7 @@ static void STDMETHODCALLTYPE d3d11_immediate_context_SwapDeviceContextState(ID3 if ((state_impl = impl_from_ID3DDeviceContextState(state))) { d3d11_immediate_context_restore_state(iface, state_impl); - device->emulated_interface = state_impl->emulated_interface; + device->state->emulated_interface = state_impl->emulated_interface; if (d3d_device_is_d3d10_active(device)) FIXME("D3D10 interface emulation not fully implemented yet!\n"); } @@ -4175,6 +4206,7 @@ static ULONG STDMETHODCALLTYPE d3d_device_inner_Release(IUnknown *iface)
if (!refcount) { + if (device->state) d3d_device_context_state_private_release(device->state); d3d11_immediate_context_destroy(&device->immediate_context); if (device->wined3d_device) { @@ -6352,6 +6384,8 @@ static void CDECL device_parent_wined3d_device_created(struct wined3d_device_par struct wined3d_device *wined3d_device) { struct d3d_device *device = device_from_wined3d_device_parent(device_parent); + ID3DDeviceContextState *state; + HRESULT hr;
TRACE("device_parent %p, wined3d_device %p.\n", device_parent, wined3d_device);
@@ -6359,6 +6393,17 @@ static void CDECL device_parent_wined3d_device_created(struct wined3d_device_par device->wined3d_device = wined3d_device;
device->feature_level = d3d_feature_level_from_wined3d(wined3d_device_get_feature_level(wined3d_device)); + + if (FAILED(hr = d3d11_device_CreateDeviceContextState(&device->ID3D11Device2_iface, 0, &device->feature_level, + 1, D3D11_SDK_VERSION, device->d3d11_only ? &IID_ID3D11Device2 : &IID_ID3D10Device1, NULL, + &state))) + ERR("Failed to create the initial device context state, hr %#x.\n", hr); + else + { + device->state = impl_from_ID3DDeviceContextState(state); + d3d_device_context_state_private_addref(device->state); + ID3DDeviceContextState_Release(state); + } }
static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent) @@ -6488,7 +6533,7 @@ void d3d_device_init(struct d3d_device *device, void *outer_unknown) /* COM aggregation always takes place */ device->outer_unk = outer_unknown; device->d3d11_only = FALSE; - device->emulated_interface = GUID_NULL; + device->state = NULL;
d3d11_immediate_context_init(&device->immediate_context, device); ID3D11DeviceContext1_Release(&device->immediate_context.ID3D11DeviceContext1_iface);
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=85667
Your paranoid android.
=== w7u_el (32 bit report) ===
d3d11: 0a60:d3d11: unhandled exception c0000005 at 7FF9615D
=== w1064v1809 (32 bit report) ===
d3d11: d3d11.c:5811: Test failed: Got unexpected IAVertices count: 0. d3d11.c:5812: Test failed: Got unexpected IAPrimitives count: 0. d3d11.c:5813: Test failed: Got unexpected VSInvocations count: 0. d3d11.c:5816: Test failed: Got unexpected CInvocations count: 0. d3d11.c:5817: Test failed: Got unexpected CPrimitives count: 0.
=== w1064 (32 bit report) ===
d3d11: d3d11.c:5811: Test failed: Got unexpected IAVertices count: 0. d3d11.c:5812: Test failed: Got unexpected IAPrimitives count: 0. d3d11.c:5813: Test failed: Got unexpected VSInvocations count: 0. d3d11.c:5816: Test failed: Got unexpected CInvocations count: 0. d3d11.c:5817: Test failed: Got unexpected CPrimitives count: 0.
=== w10pro64 (32 bit report) ===
d3d11: d3d11.c:5658: Test failed: Got unexpected query result 0x0000000000000000. d3d11.c:5811: Test failed: Got unexpected IAVertices count: 0. d3d11.c:5812: Test failed: Got unexpected IAPrimitives count: 0. d3d11.c:5813: Test failed: Got unexpected VSInvocations count: 0. d3d11.c:5816: Test failed: Got unexpected CInvocations count: 0. d3d11.c:5817: Test failed: Got unexpected CPrimitives count: 0.