From: Stefan Dösinger Subject: [PATCH 6/6] d3d9: Decouple d3d9 volumes from wined3d volumes. Message-Id: <1397742453-22083-6-git-send-email-stefan@codeweavers.com> Date: Thu, 17 Apr 2014 15:47:33 +0200 Releasing the partially created texture in case of an out of memory error is a problem, see volumetexture_init. My choice to handle this would be to move the memory allocation into the init function (and rename it), but a few years ago Henri has changed it into the opposite direction everywhere. I'm open to other suggestions. (And no, I don't like the idea of calculating the mipmap levels before calling wined3d_texture_create.) --- dlls/d3d9/d3d9_private.h | 10 +++-- dlls/d3d9/device.c | 15 +------ dlls/d3d9/texture.c | 108 ++++++++++++++++++++++++++++++++--------------- dlls/d3d9/volume.c | 30 ++----------- 4 files changed, 85 insertions(+), 78 deletions(-) diff --git a/dlls/d3d9/d3d9_private.h b/dlls/d3d9/d3d9_private.h index 389cc95..2f59a2f 100644 --- a/dlls/d3d9/d3d9_private.h +++ b/dlls/d3d9/d3d9_private.h @@ -184,14 +184,13 @@ struct d3d9_volume { IDirect3DVolume9 IDirect3DVolume9_iface; struct d3d9_resource resource; - struct wined3d_volume *wined3d_volume; IUnknown *container; IUnknown *forwardReference; UINT level; }; -void volume_init(struct d3d9_volume *volume, struct wined3d_volume *wined3d_volume, - UINT level, const struct wined3d_parent_ops **parent_ops) DECLSPEC_HIDDEN; +void d3d9_volume_init(struct d3d9_volume *volume, UINT level) DECLSPEC_HIDDEN; +void d3d9_volume_destroy(void *sub_resource) DECLSPEC_HIDDEN; struct d3d9_swapchain { @@ -251,6 +250,11 @@ struct d3d9_texture struct d3d9_resource resource; struct wined3d_texture *wined3d_texture; IDirect3DDevice9Ex *parent_device; + + void **sub_resource; + void (*sub_resource_destroy)(void *sub_resource); + UINT level_count, sub_resource_count; + BOOL error_cleanup; }; HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *device, diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 84184ec..11e13c5 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -3448,22 +3448,11 @@ static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent * void *container_parent, struct wined3d_volume *volume, UINT level, void **parent, const struct wined3d_parent_ops **parent_ops) { - struct d3d9_volume *d3d_volume; - TRACE("device_parent %p, container_parent %p, volume %p, parent %p, parent_ops %p.\n", device_parent, container_parent, volume, parent, parent_ops); - if (!(d3d_volume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_volume)))) - return E_OUTOFMEMORY; - - volume_init(d3d_volume, volume, level, parent_ops); - *parent = d3d_volume; - TRACE("Created volume %p.\n", d3d_volume); - - d3d_volume->container = container_parent; - - IDirect3DVolume9_Release(&d3d_volume->IDirect3DVolume9_iface); - d3d_volume->forwardReference = container_parent; + *parent_ops = &d3d9_null_wined3d_parent_ops; + *parent = container_parent; return D3D_OK; } diff --git a/dlls/d3d9/texture.c b/dlls/d3d9/texture.c index 7e8dd68..03c75fa 100644 --- a/dlls/d3d9/texture.c +++ b/dlls/d3d9/texture.c @@ -1018,15 +1018,9 @@ static DWORD WINAPI d3d9_texture_3d_GetLOD(IDirect3DVolumeTexture9 *iface) static DWORD WINAPI d3d9_texture_3d_GetLevelCount(IDirect3DVolumeTexture9 *iface) { struct d3d9_texture *texture = impl_from_IDirect3DVolumeTexture9(iface); - DWORD ret; TRACE("iface %p.\n", iface); - - wined3d_mutex_lock(); - ret = wined3d_texture_get_level_count(texture->wined3d_texture); - wined3d_mutex_unlock(); - - return ret; + return texture->level_count; } static HRESULT WINAPI d3d9_texture_3d_SetAutoGenFilterType(IDirect3DVolumeTexture9 *iface, @@ -1073,55 +1067,48 @@ static void WINAPI d3d9_texture_3d_GenerateMipSubLevels(IDirect3DVolumeTexture9 static HRESULT WINAPI d3d9_texture_3d_GetLevelDesc(IDirect3DVolumeTexture9 *iface, UINT level, D3DVOLUME_DESC *desc) { struct d3d9_texture *texture = impl_from_IDirect3DVolumeTexture9(iface); - HRESULT hr = D3D_OK; - DWORD level_count; + struct wined3d_resource *resource = wined3d_texture_get_resource(texture->wined3d_texture); + struct wined3d_resource_desc wined3d_desc; TRACE("iface %p, level %u, desc %p.\n", iface, level, desc); - wined3d_mutex_lock(); - level_count = wined3d_texture_get_level_count(texture->wined3d_texture); - if (level >= level_count) + if (level >= texture->level_count) { WARN("Invalid mipmap level specified, returning D3DERR_INVALIDCALL.\n"); - hr = D3DERR_INVALIDCALL; + return D3DERR_INVALIDCALL; } - else - { - struct wined3d_resource *resource = wined3d_texture_get_resource(texture->wined3d_texture); - struct wined3d_resource_desc wined3d_desc; - wined3d_resource_get_desc(resource, &wined3d_desc); - desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format); - desc->Type = D3DRTYPE_VOLUME; - desc->Usage = wined3d_desc.usage & WINED3DUSAGE_MASK; - desc->Pool = wined3d_desc.pool; - desc->Width = max(wined3d_desc.width >> level, 1); - desc->Height = max(wined3d_desc.height >> level, 1); - desc->Depth = max(wined3d_desc.depth >> level, 1); - hr = D3D_OK; - } + wined3d_mutex_lock(); + wined3d_resource_get_desc(resource, &wined3d_desc); + desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format); + desc->Type = D3DRTYPE_VOLUME; + desc->Usage = wined3d_desc.usage & WINED3DUSAGE_MASK; + desc->Pool = wined3d_desc.pool; + desc->Width = max(wined3d_desc.width >> level, 1); + desc->Height = max(wined3d_desc.height >> level, 1); + desc->Depth = max(wined3d_desc.depth >> level, 1); wined3d_mutex_unlock(); - return hr; + return D3D_OK; } static HRESULT WINAPI d3d9_texture_3d_GetVolumeLevel(IDirect3DVolumeTexture9 *iface, UINT level, IDirect3DVolume9 **volume) { struct d3d9_texture *texture = impl_from_IDirect3DVolumeTexture9(iface); - struct wined3d_resource *sub_resource; struct d3d9_volume *volume_impl; TRACE("iface %p, level %u, volume %p.\n", iface, level, volume); wined3d_mutex_lock(); - if (!(sub_resource = wined3d_texture_get_sub_resource(texture->wined3d_texture, level))) + if (level >= texture->level_count) { + WARN("Invalid mipmap level specified, returning D3DERR_INVALIDCALL.\n"); wined3d_mutex_unlock(); return D3DERR_INVALIDCALL; } - volume_impl = wined3d_resource_get_parent(sub_resource); + volume_impl = texture->sub_resource[level]; *volume = &volume_impl->IDirect3DVolume9_iface; IDirect3DVolume9_AddRef(*volume); wined3d_mutex_unlock(); @@ -1234,9 +1221,18 @@ struct d3d9_texture *unsafe_impl_from_IDirect3DBaseTexture9(IDirect3DBaseTexture static void STDMETHODCALLTYPE d3d9_texture_wined3d_object_destroyed(void *parent) { + UINT i; struct d3d9_texture *texture = parent; d3d9_resource_cleanup(&texture->resource); - HeapFree(GetProcessHeap(), 0, texture); + + if (texture->sub_resource) + { + for (i = 0; i < texture->sub_resource_count && texture->sub_resource[i]; i++) + texture->sub_resource_destroy(texture->sub_resource[i]); + HeapFree(GetProcessHeap(), 0, texture->sub_resource); + } + if (!texture->error_cleanup) + HeapFree(GetProcessHeap(), 0, texture); } static const struct wined3d_parent_ops d3d9_texture_wined3d_parent_ops = @@ -1331,6 +1327,7 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev { struct wined3d_resource_desc desc; HRESULT hr; + DWORD i; texture->IDirect3DBaseTexture9_iface.lpVtbl = (const IDirect3DBaseTexture9Vtbl *)&d3d9_texture_3d_vtbl; d3d9_resource_init(&texture->resource); @@ -1350,15 +1347,56 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev wined3d_mutex_lock(); hr = wined3d_texture_create(device->wined3d_device, &desc, levels, 0, texture, &d3d9_texture_wined3d_parent_ops, &texture->wined3d_texture); - wined3d_mutex_unlock(); if (FAILED(hr)) { WARN("Failed to create wined3d volume texture, hr %#x.\n", hr); - return hr; + goto error; + } + + texture->level_count = wined3d_texture_get_level_count(texture->wined3d_texture); + texture->sub_resource_count = texture->level_count; + + texture->sub_resource_destroy = d3d9_volume_destroy; + texture->sub_resource = HeapAlloc(GetProcessHeap(), 0, + sizeof(*texture->sub_resource) * texture->sub_resource_count); + if (!texture->sub_resource) + { + hr = E_OUTOFMEMORY; + goto error; + } + + for (i = 0; i < texture->level_count; i++) + { + struct d3d9_volume *d3d9_volume; + + if (!(d3d9_volume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d9_volume)))) + { + hr = E_OUTOFMEMORY; + goto error; + } + d3d9_volume_init(d3d9_volume, i); + TRACE("Created volume %p.\n", d3d9_volume); + + d3d9_volume->container = (IUnknown *)&texture->IDirect3DBaseTexture9_iface; + IDirect3DVolume9_Release(&d3d9_volume->IDirect3DVolume9_iface); + d3d9_volume->forwardReference = d3d9_volume->container; + texture->sub_resource[i] = d3d9_volume; } texture->parent_device = &device->IDirect3DDevice9Ex_iface; IDirect3DDevice9Ex_AddRef(texture->parent_device); - + wined3d_mutex_unlock(); return D3D_OK; + +error: + /* Once the wined3d texture is created there is no way to destroy it without running + * d3d9_texture_wined3d_object_destroyed. The caller expects volumetexture_init not + * to free texture in case of an error. */ + if (texture->wined3d_texture) + { + texture->error_cleanup = TRUE; + wined3d_texture_decref(texture->wined3d_texture); + } + wined3d_mutex_unlock(); + return hr; } diff --git a/dlls/d3d9/volume.c b/dlls/d3d9/volume.c index 07f15ca..916a949 100644 --- a/dlls/d3d9/volume.c +++ b/dlls/d3d9/volume.c @@ -63,13 +63,6 @@ static ULONG WINAPI d3d9_volume_AddRef(IDirect3DVolume9 *iface) refcount = InterlockedIncrement(&volume->resource.refcount); TRACE("%p increasing refcount to %u.\n", iface, refcount); - if (refcount == 1) - { - wined3d_mutex_lock(); - wined3d_volume_incref(volume->wined3d_volume); - wined3d_mutex_unlock(); - } - return refcount; } @@ -89,13 +82,6 @@ static ULONG WINAPI d3d9_volume_Release(IDirect3DVolume9 *iface) refcount = InterlockedDecrement(&volume->resource.refcount); TRACE("%p decreasing refcount to %u.\n", iface, refcount); - if (!refcount) - { - wined3d_mutex_lock(); - wined3d_volume_decref(volume->wined3d_volume); - wined3d_mutex_unlock(); - } - return refcount; } @@ -213,26 +199,16 @@ static const struct IDirect3DVolume9Vtbl d3d9_volume_vtbl = d3d9_volume_UnlockBox, }; -static void STDMETHODCALLTYPE volume_wined3d_object_destroyed(void *parent) +void d3d9_volume_destroy(void *sub_resource) { - struct d3d9_volume *volume = parent; + struct d3d9_volume *volume = sub_resource; d3d9_resource_cleanup(&volume->resource); HeapFree(GetProcessHeap(), 0, volume); } -static const struct wined3d_parent_ops d3d9_volume_wined3d_parent_ops = -{ - volume_wined3d_object_destroyed, -}; - -void volume_init(struct d3d9_volume *volume, struct wined3d_volume *wined3d_volume, - UINT level, const struct wined3d_parent_ops **parent_ops) +void d3d9_volume_init(struct d3d9_volume *volume, UINT level) { volume->IDirect3DVolume9_iface.lpVtbl = &d3d9_volume_vtbl; d3d9_resource_init(&volume->resource); - wined3d_volume_incref(wined3d_volume); - volume->wined3d_volume = wined3d_volume; volume->level = level; - - *parent_ops = &d3d9_volume_wined3d_parent_ops; } -- 1.8.3.2