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);