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:
parent
ba67df7a60
commit
5fc17b84d0
|
@ -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) {
|
||||
if (!ref)
|
||||
{
|
||||
unsigned i;
|
||||
This->inDestruction = TRUE;
|
||||
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]);
|
||||
for (i = 0; i < device->fvf_decl_count; ++i)
|
||||
{
|
||||
wined3d_vertex_declaration_decref(device->fvf_decls[i].decl);
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, This->convertedDecls);
|
||||
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_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) {
|
||||
low = p + 1;
|
||||
} else {
|
||||
high = p - 1;
|
||||
|
||||
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
|
||||
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;
|
||||
if (FAILED(hr = vdecl_convert_fvf(fvf, &elements)))
|
||||
return NULL;
|
||||
|
||||
hr = IDirect3DDevice9Impl_CreateVertexDeclaration(&This->IDirect3DDevice9Ex_iface, elements,
|
||||
&pDecl);
|
||||
HeapFree(GetProcessHeap(), 0, elements); /* CreateVertexDeclaration makes a copy */
|
||||
if (hr != S_OK) return NULL;
|
||||
hr = d3d9_vertex_declaration_create(device, elements, &d3d9_declaration);
|
||||
HeapFree(GetProcessHeap(), 0, elements);
|
||||
if (FAILED(hr))
|
||||
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 (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);
|
||||
|
||||
/* Will prevent the decl from being destroyed */
|
||||
((IDirect3DVertexDeclaration9Impl *) pDecl)->convFVF = fvf;
|
||||
IDirect3DVertexDeclaration9_Release(pDecl); /* Does not destroy now */
|
||||
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;
|
||||
|
||||
TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
|
||||
return pDecl;
|
||||
TRACE("Returning %p. %u declatations in array.\n", wined3d_declaration, device->fvf_decl_count);
|
||||
|
||||
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");
|
||||
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) {
|
||||
IDirect3DDevice9Ex_AddRef(This->parentDevice);
|
||||
if (!This->convFVF)
|
||||
if (ref == 1)
|
||||
{
|
||||
IDirect3DDevice9Ex_AddRef(This->parentDevice);
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue