From 0ffda86f761bb3b94133e8b4363baa9ffa73af2f Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Thu, 13 Dec 2012 22:08:59 +0100 Subject: [PATCH] d3d10core: Only create unique depthstencil state objects. --- dlls/d3d10core/d3d10core_private.h | 5 +++- dlls/d3d10core/device.c | 41 +++++++++++++++++++++++++++++- dlls/d3d10core/state.c | 19 ++++++++++---- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/dlls/d3d10core/d3d10core_private.h b/dlls/d3d10core/d3d10core_private.h index 391207b6126..b5ba293640c 100644 --- a/dlls/d3d10core/d3d10core_private.h +++ b/dlls/d3d10core/d3d10core_private.h @@ -232,10 +232,12 @@ struct d3d10_depthstencil_state ID3D10DepthStencilState ID3D10DepthStencilState_iface; LONG refcount; + struct d3d10_device *device; D3D10_DEPTH_STENCIL_DESC desc; + struct wine_rb_entry entry; }; -HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, +HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, struct d3d10_device *device, const D3D10_DEPTH_STENCIL_DESC *desc) DECLSPEC_HIDDEN; struct d3d10_depthstencil_state *unsafe_impl_from_ID3D10DepthStencilState( ID3D10DepthStencilState *iface) DECLSPEC_HIDDEN; @@ -288,6 +290,7 @@ struct d3d10_device struct wined3d_device *wined3d_device; struct wine_rb_tree blend_states; + struct wine_rb_tree depthstencil_states; struct wine_rb_tree sampler_states; struct d3d10_blend_state *blend_state; diff --git a/dlls/d3d10core/device.c b/dlls/d3d10core/device.c index 13bd9a6a5f6..bcf49dabfe4 100644 --- a/dlls/d3d10core/device.c +++ b/dlls/d3d10core/device.c @@ -82,6 +82,7 @@ static ULONG STDMETHODCALLTYPE d3d10_device_inner_Release(IUnknown *iface) if (device->wined3d_device) wined3d_device_decref(device->wined3d_device); wine_rb_destroy(&device->sampler_states, NULL, NULL); + wine_rb_destroy(&device->depthstencil_states, NULL, NULL); wine_rb_destroy(&device->blend_states, NULL, NULL); } @@ -1430,7 +1431,9 @@ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateBlendState(ID3D10Device *ifa static HRESULT STDMETHODCALLTYPE d3d10_device_CreateDepthStencilState(ID3D10Device *iface, const D3D10_DEPTH_STENCIL_DESC *desc, ID3D10DepthStencilState **depth_stencil_state) { + struct d3d10_device *device = impl_from_ID3D10Device(iface); struct d3d10_depthstencil_state *object; + struct wine_rb_entry *entry; HRESULT hr; TRACE("iface %p, desc %p, depth_stencil_state %p.\n", iface, desc, depth_stencil_state); @@ -1438,6 +1441,17 @@ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateDepthStencilState(ID3D10Devi if (!desc) return E_INVALIDARG; + if ((entry = wine_rb_get(&device->depthstencil_states, desc))) + { + object = WINE_RB_ENTRY_VALUE(entry, struct d3d10_depthstencil_state, entry); + + TRACE("Returning existing depthstencil state %p.\n", object); + *depth_stencil_state = &object->ID3D10DepthStencilState_iface; + ID3D10DepthStencilState_AddRef(*depth_stencil_state); + + return S_OK; + } + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); if (!object) { @@ -1445,7 +1459,7 @@ static HRESULT STDMETHODCALLTYPE d3d10_device_CreateDepthStencilState(ID3D10Devi return E_OUTOFMEMORY; } - if (FAILED(hr = d3d10_depthstencil_state_init(object, desc))) + if (FAILED(hr = d3d10_depthstencil_state_init(object, device, desc))) { WARN("Failed to initialize depthstencil state, hr %#x.\n", hr); HeapFree(GetProcessHeap(), 0, object); @@ -1987,6 +2001,23 @@ static const struct wine_rb_functions d3d10_blend_state_rb_ops = d3d10_blend_state_compare, }; +static int d3d10_depthstencil_state_compare(const void *key, const struct wine_rb_entry *entry) +{ + const D3D10_DEPTH_STENCIL_DESC *ka = key; + const D3D10_DEPTH_STENCIL_DESC *kb = &WINE_RB_ENTRY_VALUE(entry, + const struct d3d10_depthstencil_state, entry)->desc; + + return memcmp(ka, kb, sizeof(*ka)); +} + +static const struct wine_rb_functions d3d10_depthstencil_state_rb_ops = +{ + d3d10_rb_alloc, + d3d10_rb_realloc, + d3d10_rb_free, + d3d10_depthstencil_state_compare, +}; + HRESULT d3d10_device_init(struct d3d10_device *device, void *outer_unknown) { device->ID3D10Device_iface.lpVtbl = &d3d10_device_vtbl; @@ -2003,9 +2034,17 @@ HRESULT d3d10_device_init(struct d3d10_device *device, void *outer_unknown) return E_FAIL; } + if (wine_rb_init(&device->depthstencil_states, &d3d10_depthstencil_state_rb_ops) == -1) + { + WARN("Failed to initialize depthstencil state rbtree.\n"); + wine_rb_destroy(&device->blend_states, NULL, NULL); + return E_FAIL; + } + if (wine_rb_init(&device->sampler_states, &d3d10_sampler_state_rb_ops) == -1) { WARN("Failed to initialize sampler state rbtree.\n"); + wine_rb_destroy(&device->depthstencil_states, NULL, NULL); wine_rb_destroy(&device->blend_states, NULL, NULL); return E_FAIL; } diff --git a/dlls/d3d10core/state.c b/dlls/d3d10core/state.c index a34df328bd1..b2aebdcf380 100644 --- a/dlls/d3d10core/state.c +++ b/dlls/d3d10core/state.c @@ -202,14 +202,15 @@ static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_AddRef(ID3D10DepthStenci static ULONG STDMETHODCALLTYPE d3d10_depthstencil_state_Release(ID3D10DepthStencilState *iface) { - struct d3d10_depthstencil_state *This = impl_from_ID3D10DepthStencilState(iface); - ULONG refcount = InterlockedDecrement(&This->refcount); + struct d3d10_depthstencil_state *state = impl_from_ID3D10DepthStencilState(iface); + ULONG refcount = InterlockedDecrement(&state->refcount); - TRACE("%p decreasing refcount to %u.\n", This, refcount); + TRACE("%p decreasing refcount to %u.\n", state, refcount); if (!refcount) { - HeapFree(GetProcessHeap(), 0, This); + wine_rb_remove(&state->device->depthstencil_states, &state->desc); + HeapFree(GetProcessHeap(), 0, state); } return refcount; @@ -275,12 +276,20 @@ static const struct ID3D10DepthStencilStateVtbl d3d10_depthstencil_state_vtbl = d3d10_depthstencil_state_GetDesc, }; -HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, const D3D10_DEPTH_STENCIL_DESC *desc) +HRESULT d3d10_depthstencil_state_init(struct d3d10_depthstencil_state *state, struct d3d10_device *device, + const D3D10_DEPTH_STENCIL_DESC *desc) { state->ID3D10DepthStencilState_iface.lpVtbl = &d3d10_depthstencil_state_vtbl; state->refcount = 1; + state->device = device; state->desc = *desc; + if (wine_rb_put(&device->depthstencil_states, desc, &state->entry) == -1) + { + ERR("Failed to insert depthstencil state entry.\n"); + return E_FAIL; + } + return S_OK; }