d3d9: Store wined3d vertex declarations in the fvf lookup table.

This also implicitly gets rid of the convFVF hack in
IDirect3DVertexDeclaration9Impl_Release().
This commit is contained in:
Henri Verbeet 2012-04-11 22:52:03 +02:00 committed by Alexandre Julliard
parent ba67df7a60
commit 5fc17b84d0
3 changed files with 102 additions and 101 deletions

View File

@ -156,6 +156,12 @@ typedef struct IDirect3D9Impl
void filter_caps(D3DCAPS9* pCaps) DECLSPEC_HIDDEN; void filter_caps(D3DCAPS9* pCaps) DECLSPEC_HIDDEN;
struct fvf_declaration
{
struct wined3d_vertex_declaration *decl;
DWORD fvf;
};
/***************************************************************************** /*****************************************************************************
* IDirect3DDevice9 implementation structure * IDirect3DDevice9 implementation structure
*/ */
@ -169,8 +175,8 @@ typedef struct IDirect3DDevice9Impl
/* Avoids recursion with nested ReleaseRef to 0 */ /* Avoids recursion with nested ReleaseRef to 0 */
BOOL inDestruction; BOOL inDestruction;
IDirect3DVertexDeclaration9 **convertedDecls; struct fvf_declaration *fvf_decls;
unsigned int numConvertedDecls, declArraySize; UINT fvf_decl_count, fvf_decl_size;
BOOL notreset; BOOL notreset;
BOOL in_scene; BOOL in_scene;
@ -394,7 +400,6 @@ typedef struct IDirect3DVertexDeclaration9Impl {
LPDIRECT3DDEVICE9EX parentDevice; LPDIRECT3DDEVICE9EX parentDevice;
} IDirect3DVertexDeclaration9Impl; } IDirect3DVertexDeclaration9Impl;
void IDirect3DVertexDeclaration9Impl_Destroy(LPDIRECT3DVERTEXDECLARATION9 iface) DECLSPEC_HIDDEN;
HRESULT d3d9_vertex_declaration_create(IDirect3DDevice9Impl *device, HRESULT d3d9_vertex_declaration_create(IDirect3DDevice9Impl *device,
const D3DVERTEXELEMENT9 *elements, IDirect3DVertexDeclaration9Impl **declaration) DECLSPEC_HIDDEN; const D3DVERTEXELEMENT9 *elements, IDirect3DVertexDeclaration9Impl **declaration) DECLSPEC_HIDDEN;

View File

@ -234,36 +234,38 @@ static ULONG WINAPI IDirect3DDevice9Impl_AddRef(IDirect3DDevice9Ex *iface)
static ULONG WINAPI DECLSPEC_HOTPATCH IDirect3DDevice9Impl_Release(IDirect3DDevice9Ex *iface) static ULONG WINAPI DECLSPEC_HOTPATCH IDirect3DDevice9Impl_Release(IDirect3DDevice9Ex *iface)
{ {
IDirect3DDevice9Impl *This = impl_from_IDirect3DDevice9Ex(iface); IDirect3DDevice9Impl *device = impl_from_IDirect3DDevice9Ex(iface);
ULONG ref; ULONG ref;
if (This->inDestruction) return 0; if (device->inDestruction)
ref = InterlockedDecrement(&This->ref); return 0;
ref = InterlockedDecrement(&device->ref);
TRACE("%p decreasing refcount to %u.\n", iface, ref); TRACE("%p decreasing refcount to %u.\n", iface, ref);
if (ref == 0) { if (!ref)
unsigned i; {
This->inDestruction = TRUE; unsigned i;
device->inDestruction = TRUE;
wined3d_mutex_lock(); wined3d_mutex_lock();
for(i = 0; i < This->numConvertedDecls; i++) { for (i = 0; i < device->fvf_decl_count; ++i)
/* Unless Wine is buggy or the app has a bug the refcount will be 0, because decls hold a reference to the {
* device wined3d_vertex_declaration_decref(device->fvf_decls[i].decl);
*/ }
IDirect3DVertexDeclaration9Impl_Destroy(This->convertedDecls[i]); HeapFree(GetProcessHeap(), 0, device->fvf_decls);
}
HeapFree(GetProcessHeap(), 0, This->convertedDecls);
wined3d_device_uninit_3d(This->wined3d_device); wined3d_device_uninit_3d(device->wined3d_device);
wined3d_device_release_focus_window(This->wined3d_device); wined3d_device_release_focus_window(device->wined3d_device);
wined3d_device_decref(This->wined3d_device); wined3d_device_decref(device->wined3d_device);
wined3d_mutex_unlock(); wined3d_mutex_unlock();
IDirect3D9Ex_Release(&This->d3d_parent->IDirect3D9Ex_iface); IDirect3D9Ex_Release(&device->d3d_parent->IDirect3D9Ex_iface);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, device);
} }
return ref; return ref;
} }
@ -2136,91 +2138,100 @@ static HRESULT WINAPI IDirect3DDevice9Impl_GetVertexDeclaration(IDirect3DDevice9
return hr; return hr;
} }
static IDirect3DVertexDeclaration9 *getConvertedDecl(IDirect3DDevice9Impl *This, DWORD fvf) { static struct wined3d_vertex_declaration *device_get_fvf_declaration(IDirect3DDevice9Impl *device, DWORD fvf)
HRESULT hr; {
D3DVERTEXELEMENT9* elements = NULL; struct wined3d_vertex_declaration *wined3d_declaration;
IDirect3DVertexDeclaration9* pDecl = NULL; struct fvf_declaration *fvf_decls = device->fvf_decls;
IDirect3DVertexDeclaration9Impl *d3d9_declaration;
D3DVERTEXELEMENT9 *elements;
int p, low, high; /* deliberately signed */ int p, low, high; /* deliberately signed */
IDirect3DVertexDeclaration9 **convertedDecls = This->convertedDecls; HRESULT hr;
TRACE("Searching for declaration for fvf %08x... ", fvf); TRACE("Searching for declaration for fvf %08x... ", fvf);
low = 0; low = 0;
high = This->numConvertedDecls - 1; high = device->fvf_decl_count - 1;
while(low <= high) { while (low <= high)
{
p = (low + high) >> 1; p = (low + high) >> 1;
TRACE("%d ", p); TRACE("%d ", p);
if(((IDirect3DVertexDeclaration9Impl *) convertedDecls[p])->convFVF == fvf) {
TRACE("found %p\n", convertedDecls[p]); if (fvf_decls[p].fvf == fvf)
return convertedDecls[p]; {
} else if(((IDirect3DVertexDeclaration9Impl *) convertedDecls[p])->convFVF < fvf) { TRACE("found %p.\n", fvf_decls[p].decl);
low = p + 1; return fvf_decls[p].decl;
} else {
high = p - 1;
} }
if (fvf_decls[p].fvf < fvf)
low = p + 1;
else
high = p - 1;
} }
TRACE("not found. Creating and inserting at position %d.\n", low); TRACE("not found. Creating and inserting at position %d.\n", low);
hr = vdecl_convert_fvf(fvf, &elements); if (FAILED(hr = vdecl_convert_fvf(fvf, &elements)))
if (hr != S_OK) return NULL; return NULL;
hr = IDirect3DDevice9Impl_CreateVertexDeclaration(&This->IDirect3DDevice9Ex_iface, elements, hr = d3d9_vertex_declaration_create(device, elements, &d3d9_declaration);
&pDecl); HeapFree(GetProcessHeap(), 0, elements);
HeapFree(GetProcessHeap(), 0, elements); /* CreateVertexDeclaration makes a copy */ if (FAILED(hr))
if (hr != S_OK) return NULL; return NULL;
if(This->declArraySize == This->numConvertedDecls) { if (device->fvf_decl_size == device->fvf_decl_count)
int grow = max(This->declArraySize / 2, 8); {
convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls, UINT grow = max(device->fvf_decl_size / 2, 8);
sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow));
if(!convertedDecls) { fvf_decls = HeapReAlloc(GetProcessHeap(), 0, fvf_decls, sizeof(*fvf_decls) * (device->fvf_decl_size + grow));
/* This will destroy it */ if (!fvf_decls)
IDirect3DVertexDeclaration9_Release(pDecl); {
IDirect3DVertexDeclaration9_Release((IDirect3DVertexDeclaration9 *)d3d9_declaration);
return NULL; return NULL;
} }
This->convertedDecls = convertedDecls; device->fvf_decls = fvf_decls;
This->declArraySize += grow; device->fvf_decl_size += grow;
} }
memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(IDirect3DVertexDeclaration9Impl *) * (This->numConvertedDecls - low)); d3d9_declaration->convFVF = fvf;
convertedDecls[low] = pDecl; wined3d_declaration = d3d9_declaration->wineD3DVertexDeclaration;
This->numConvertedDecls++; wined3d_vertex_declaration_incref(wined3d_declaration);
IDirect3DVertexDeclaration9_Release((IDirect3DVertexDeclaration9 *)d3d9_declaration);
/* Will prevent the decl from being destroyed */ memmove(fvf_decls + low + 1, fvf_decls + low, sizeof(*fvf_decls) * (device->fvf_decl_count - low));
((IDirect3DVertexDeclaration9Impl *) pDecl)->convFVF = fvf; fvf_decls[low].decl = wined3d_declaration;
IDirect3DVertexDeclaration9_Release(pDecl); /* Does not destroy now */ fvf_decls[low].fvf = fvf;
++device->fvf_decl_count;
TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls); TRACE("Returning %p. %u declatations in array.\n", wined3d_declaration, device->fvf_decl_count);
return pDecl;
return wined3d_declaration;
} }
static HRESULT WINAPI IDirect3DDevice9Impl_SetFVF(IDirect3DDevice9Ex *iface, DWORD FVF) static HRESULT WINAPI IDirect3DDevice9Impl_SetFVF(IDirect3DDevice9Ex *iface, DWORD fvf)
{ {
IDirect3DDevice9Impl *This = impl_from_IDirect3DDevice9Ex(iface); IDirect3DDevice9Impl *This = impl_from_IDirect3DDevice9Ex(iface);
IDirect3DVertexDeclaration9 *decl; struct wined3d_vertex_declaration *decl;
HRESULT hr; HRESULT hr;
TRACE("iface %p, fvf %#x.\n", iface, FVF); TRACE("iface %p, fvf %#x.\n", iface, fvf);
if (!FVF) if (!fvf)
{ {
WARN("%#x is not a valid FVF\n", FVF); WARN("%#x is not a valid FVF.\n", fvf);
return D3D_OK; return D3D_OK;
} }
wined3d_mutex_lock(); wined3d_mutex_lock();
decl = getConvertedDecl(This, FVF); if (!(decl = device_get_fvf_declaration(This, fvf)))
wined3d_mutex_unlock();
if (!decl)
{ {
/* Any situation when this should happen, except out of memory? */ wined3d_mutex_unlock();
ERR("Failed to create a converted vertex declaration\n"); ERR("Failed to create a vertex declaration for fvf %#x.\n", fvf);
return D3DERR_DRIVERINTERNALERROR; return D3DERR_DRIVERINTERNALERROR;
} }
hr = IDirect3DDevice9Impl_SetVertexDeclaration(iface, decl); hr = wined3d_device_set_vertex_declaration(This->wined3d_device, decl);
if (FAILED(hr)) ERR("Failed to set vertex declaration\n"); if (FAILED(hr))
ERR("Failed to set vertex declaration.\n");
wined3d_mutex_unlock();
return hr; return hr;
} }
@ -3466,8 +3477,8 @@ HRESULT device_init(IDirect3DDevice9Impl *device, IDirect3D9Impl *parent, struct
/* Initialize the converted declaration array. This creates a valid pointer /* Initialize the converted declaration array. This creates a valid pointer
* and when adding decls HeapReAlloc() can be used without further checking. */ * and when adding decls HeapReAlloc() can be used without further checking. */
device->convertedDecls = HeapAlloc(GetProcessHeap(), 0, 0); device->fvf_decls = HeapAlloc(GetProcessHeap(), 0, 0);
if (!device->convertedDecls) if (!device->fvf_decls)
{ {
ERR("Failed to allocate FVF vertex declaration map memory.\n"); ERR("Failed to allocate FVF vertex declaration map memory.\n");
wined3d_mutex_lock(); wined3d_mutex_lock();

View File

@ -219,44 +219,29 @@ static ULONG WINAPI IDirect3DVertexDeclaration9Impl_AddRef(LPDIRECT3DVERTEXDECLA
TRACE("%p increasing refcount to %u.\n", iface, ref); TRACE("%p increasing refcount to %u.\n", iface, ref);
if(ref == 1) { if (ref == 1)
{
IDirect3DDevice9Ex_AddRef(This->parentDevice); IDirect3DDevice9Ex_AddRef(This->parentDevice);
if (!This->convFVF) wined3d_mutex_lock();
{ wined3d_vertex_declaration_incref(This->wineD3DVertexDeclaration);
wined3d_mutex_lock(); wined3d_mutex_unlock();
wined3d_vertex_declaration_incref(This->wineD3DVertexDeclaration);
wined3d_mutex_unlock();
}
} }
return ref; return ref;
} }
void IDirect3DVertexDeclaration9Impl_Destroy(LPDIRECT3DVERTEXDECLARATION9 iface) {
IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
if(This->ref != 0) {
/* Should not happen unless wine has a bug or the application releases references it does not own */
ERR("Destroying vdecl with ref != 0\n");
}
wined3d_mutex_lock();
wined3d_vertex_declaration_decref(This->wineD3DVertexDeclaration);
wined3d_mutex_unlock();
}
static ULONG WINAPI IDirect3DVertexDeclaration9Impl_Release(LPDIRECT3DVERTEXDECLARATION9 iface) { static ULONG WINAPI IDirect3DVertexDeclaration9Impl_Release(LPDIRECT3DVERTEXDECLARATION9 iface) {
IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface; IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
ULONG ref = InterlockedDecrement(&This->ref); ULONG ref = InterlockedDecrement(&This->ref);
TRACE("%p decreasing refcount to %u.\n", iface, ref); TRACE("%p decreasing refcount to %u.\n", iface, ref);
if (ref == 0) { if (!ref)
{
IDirect3DDevice9Ex *parentDevice = This->parentDevice; IDirect3DDevice9Ex *parentDevice = This->parentDevice;
wined3d_mutex_lock();
if(!This->convFVF) { wined3d_vertex_declaration_decref(This->wineD3DVertexDeclaration);
IDirect3DVertexDeclaration9Impl_Destroy(iface); wined3d_mutex_unlock();
}
/* Release the device last, as it may cause the device to be destroyed. */ /* Release the device last, as it may cause the device to be destroyed. */
IDirect3DDevice9Ex_Release(parentDevice); IDirect3DDevice9Ex_Release(parentDevice);