Commit 5fc17b84 authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

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

This also implicitly gets rid of the convFVF hack in IDirect3DVertexDeclaration9Impl_Release().
parent ba67df7a
......@@ -156,6 +156,12 @@ typedef struct IDirect3D9Impl
void filter_caps(D3DCAPS9* pCaps) DECLSPEC_HIDDEN;
struct fvf_declaration
{
struct wined3d_vertex_declaration *decl;
DWORD fvf;
};
/*****************************************************************************
* IDirect3DDevice9 implementation structure
*/
......@@ -169,8 +175,8 @@ typedef struct IDirect3DDevice9Impl
/* Avoids recursion with nested ReleaseRef to 0 */
BOOL inDestruction;
IDirect3DVertexDeclaration9 **convertedDecls;
unsigned int numConvertedDecls, declArraySize;
struct fvf_declaration *fvf_decls;
UINT fvf_decl_count, fvf_decl_size;
BOOL notreset;
BOOL in_scene;
......@@ -394,7 +400,6 @@ typedef struct IDirect3DVertexDeclaration9Impl {
LPDIRECT3DDEVICE9EX parentDevice;
} IDirect3DVertexDeclaration9Impl;
void IDirect3DVertexDeclaration9Impl_Destroy(LPDIRECT3DVERTEXDECLARATION9 iface) DECLSPEC_HIDDEN;
HRESULT d3d9_vertex_declaration_create(IDirect3DDevice9Impl *device,
const D3DVERTEXELEMENT9 *elements, IDirect3DVertexDeclaration9Impl **declaration) DECLSPEC_HIDDEN;
......
......@@ -234,36 +234,38 @@ static ULONG WINAPI IDirect3DDevice9Impl_AddRef(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;
if (This->inDestruction) return 0;
ref = InterlockedDecrement(&This->ref);
if (device->inDestruction)
return 0;
ref = InterlockedDecrement(&device->ref);
TRACE("%p decreasing refcount to %u.\n", iface, ref);
if (ref == 0) {
unsigned i;
This->inDestruction = TRUE;
if (!ref)
{
unsigned i;
device->inDestruction = TRUE;
wined3d_mutex_lock();
for(i = 0; i < This->numConvertedDecls; i++) {
/* Unless Wine is buggy or the app has a bug the refcount will be 0, because decls hold a reference to the
* device
*/
IDirect3DVertexDeclaration9Impl_Destroy(This->convertedDecls[i]);
}
HeapFree(GetProcessHeap(), 0, This->convertedDecls);
wined3d_mutex_lock();
for (i = 0; i < device->fvf_decl_count; ++i)
{
wined3d_vertex_declaration_decref(device->fvf_decls[i].decl);
}
HeapFree(GetProcessHeap(), 0, device->fvf_decls);
wined3d_device_uninit_3d(This->wined3d_device);
wined3d_device_release_focus_window(This->wined3d_device);
wined3d_device_decref(This->wined3d_device);
wined3d_mutex_unlock();
wined3d_device_uninit_3d(device->wined3d_device);
wined3d_device_release_focus_window(device->wined3d_device);
wined3d_device_decref(device->wined3d_device);
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;
}
......@@ -2136,91 +2138,100 @@ static HRESULT WINAPI IDirect3DDevice9Impl_GetVertexDeclaration(IDirect3DDevice9
return hr;
}
static IDirect3DVertexDeclaration9 *getConvertedDecl(IDirect3DDevice9Impl *This, DWORD fvf) {
HRESULT hr;
D3DVERTEXELEMENT9* elements = NULL;
IDirect3DVertexDeclaration9* pDecl = NULL;
static struct wined3d_vertex_declaration *device_get_fvf_declaration(IDirect3DDevice9Impl *device, DWORD fvf)
{
struct wined3d_vertex_declaration *wined3d_declaration;
struct fvf_declaration *fvf_decls = device->fvf_decls;
IDirect3DVertexDeclaration9Impl *d3d9_declaration;
D3DVERTEXELEMENT9 *elements;
int p, low, high; /* deliberately signed */
IDirect3DVertexDeclaration9 **convertedDecls = This->convertedDecls;
HRESULT hr;
TRACE("Searching for declaration for fvf %08x... ", fvf);
low = 0;
high = This->numConvertedDecls - 1;
while(low <= high) {
high = device->fvf_decl_count - 1;
while (low <= high)
{
p = (low + high) >> 1;
TRACE("%d ", p);
if(((IDirect3DVertexDeclaration9Impl *) convertedDecls[p])->convFVF == fvf) {
TRACE("found %p\n", convertedDecls[p]);
return convertedDecls[p];
} else if(((IDirect3DVertexDeclaration9Impl *) convertedDecls[p])->convFVF < fvf) {
if (fvf_decls[p].fvf == fvf)
{
TRACE("found %p.\n", fvf_decls[p].decl);
return fvf_decls[p].decl;
}
if (fvf_decls[p].fvf < fvf)
low = p + 1;
} else {
else
high = p - 1;
}
}
TRACE("not found. Creating and inserting at position %d.\n", low);
hr = vdecl_convert_fvf(fvf, &elements);
if (hr != S_OK) return NULL;
hr = IDirect3DDevice9Impl_CreateVertexDeclaration(&This->IDirect3DDevice9Ex_iface, elements,
&pDecl);
HeapFree(GetProcessHeap(), 0, elements); /* CreateVertexDeclaration makes a copy */
if (hr != S_OK) return NULL;
if(This->declArraySize == This->numConvertedDecls) {
int grow = max(This->declArraySize / 2, 8);
convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow));
if(!convertedDecls) {
/* This will destroy it */
IDirect3DVertexDeclaration9_Release(pDecl);
if (FAILED(hr = vdecl_convert_fvf(fvf, &elements)))
return NULL;
hr = d3d9_vertex_declaration_create(device, elements, &d3d9_declaration);
HeapFree(GetProcessHeap(), 0, elements);
if (FAILED(hr))
return NULL;
if (device->fvf_decl_size == device->fvf_decl_count)
{
UINT grow = max(device->fvf_decl_size / 2, 8);
fvf_decls = HeapReAlloc(GetProcessHeap(), 0, fvf_decls, sizeof(*fvf_decls) * (device->fvf_decl_size + grow));
if (!fvf_decls)
{
IDirect3DVertexDeclaration9_Release((IDirect3DVertexDeclaration9 *)d3d9_declaration);
return NULL;
}
This->convertedDecls = convertedDecls;
This->declArraySize += grow;
device->fvf_decls = fvf_decls;
device->fvf_decl_size += grow;
}
memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(IDirect3DVertexDeclaration9Impl *) * (This->numConvertedDecls - low));
convertedDecls[low] = pDecl;
This->numConvertedDecls++;
d3d9_declaration->convFVF = fvf;
wined3d_declaration = d3d9_declaration->wineD3DVertexDeclaration;
wined3d_vertex_declaration_incref(wined3d_declaration);
IDirect3DVertexDeclaration9_Release((IDirect3DVertexDeclaration9 *)d3d9_declaration);
memmove(fvf_decls + low + 1, fvf_decls + low, sizeof(*fvf_decls) * (device->fvf_decl_count - low));
fvf_decls[low].decl = wined3d_declaration;
fvf_decls[low].fvf = fvf;
++device->fvf_decl_count;
/* Will prevent the decl from being destroyed */
((IDirect3DVertexDeclaration9Impl *) pDecl)->convFVF = fvf;
IDirect3DVertexDeclaration9_Release(pDecl); /* Does not destroy now */
TRACE("Returning %p. %u declatations in array.\n", wined3d_declaration, device->fvf_decl_count);
TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
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);
IDirect3DVertexDeclaration9 *decl;
struct wined3d_vertex_declaration *decl;
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;
}
wined3d_mutex_lock();
decl = getConvertedDecl(This, FVF);
wined3d_mutex_unlock();
if (!decl)
if (!(decl = device_get_fvf_declaration(This, fvf)))
{
/* Any situation when this should happen, except out of memory? */
ERR("Failed to create a converted vertex declaration\n");
return D3DERR_DRIVERINTERNALERROR;
wined3d_mutex_unlock();
ERR("Failed to create a vertex declaration for fvf %#x.\n", fvf);
return D3DERR_DRIVERINTERNALERROR;
}
hr = IDirect3DDevice9Impl_SetVertexDeclaration(iface, decl);
if (FAILED(hr)) ERR("Failed to set vertex declaration\n");
hr = wined3d_device_set_vertex_declaration(This->wined3d_device, decl);
if (FAILED(hr))
ERR("Failed to set vertex declaration.\n");
wined3d_mutex_unlock();
return hr;
}
......@@ -3466,8 +3477,8 @@ HRESULT device_init(IDirect3DDevice9Impl *device, IDirect3D9Impl *parent, struct
/* Initialize the converted declaration array. This creates a valid pointer
* and when adding decls HeapReAlloc() can be used without further checking. */
device->convertedDecls = HeapAlloc(GetProcessHeap(), 0, 0);
if (!device->convertedDecls)
device->fvf_decls = HeapAlloc(GetProcessHeap(), 0, 0);
if (!device->fvf_decls)
{
ERR("Failed to allocate FVF vertex declaration map memory.\n");
wined3d_mutex_lock();
......
......@@ -219,44 +219,29 @@ static ULONG WINAPI IDirect3DVertexDeclaration9Impl_AddRef(LPDIRECT3DVERTEXDECLA
TRACE("%p increasing refcount to %u.\n", iface, ref);
if(ref == 1) {
if (ref == 1)
{
IDirect3DDevice9Ex_AddRef(This->parentDevice);
if (!This->convFVF)
{
wined3d_mutex_lock();
wined3d_vertex_declaration_incref(This->wineD3DVertexDeclaration);
wined3d_mutex_unlock();
}
wined3d_mutex_lock();
wined3d_vertex_declaration_incref(This->wineD3DVertexDeclaration);
wined3d_mutex_unlock();
}
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) {
IDirect3DVertexDeclaration9Impl *This = (IDirect3DVertexDeclaration9Impl *)iface;
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("%p decreasing refcount to %u.\n", iface, ref);
if (ref == 0) {
if (!ref)
{
IDirect3DDevice9Ex *parentDevice = This->parentDevice;
if(!This->convFVF) {
IDirect3DVertexDeclaration9Impl_Destroy(iface);
}
wined3d_mutex_lock();
wined3d_vertex_declaration_decref(This->wineD3DVertexDeclaration);
wined3d_mutex_unlock();
/* Release the device last, as it may cause the device to be destroyed. */
IDirect3DDevice9Ex_Release(parentDevice);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment