[PATCH 6/6] d3d9: Decouple d3d9 volumes from wined3d volumes.

Stefan Dösinger stefan at codeweavers.com
Thu Apr 17 08:47:33 CDT 2014


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




More information about the wine-patches mailing list