From a8e2b2cb691d123754cf1a180fad825cea3167f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Sun, 6 Oct 2013 16:20:32 +0200
Subject: wined3d: Clean up texture resources through the cs.

---
 dlls/wined3d/cs.c              | 28 ++++++++++++++++++++++++++++
 dlls/wined3d/texture.c         | 31 ++++++++++++++++++++++++-------
 dlls/wined3d/wined3d_private.h |  2 ++
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 819e7e2..38f8307 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -85,6 +85,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_BUFFER_CLEANUP,
     WINED3D_CS_OP_VOLUME_CLEANUP,
     WINED3D_CS_OP_SURFACE_CLEANUP,
+    WINED3D_CS_OP_TEXTURE_CLEANUP,
     WINED3D_CS_OP_STOP,
 };
 
@@ -498,6 +499,12 @@ struct wined3d_cs_surface_cleanup
     struct wined3d_surface *surface;
 };
 
+struct wined3d_cs_texture_cleanup
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_texture *texture;
+};
+
 static void wined3d_cs_mt_submit(struct wined3d_cs *cs, size_t size)
 {
     LONG new_val = (cs->queue.head + size) & (WINED3D_CS_QUEUE_SIZE - 1);
@@ -2463,6 +2470,26 @@ void wined3d_cs_emit_surface_cleanup(struct wined3d_cs *cs, struct wined3d_surfa
     cs->ops->submit(cs, sizeof(*op));
 }
 
+static UINT wined3d_cs_exec_texture_cleanup(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_texture_cleanup *op = data;
+
+    wined3d_texture_cleanup_cs(op->texture);
+
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_texture_cleanup(struct wined3d_cs *cs, struct wined3d_texture *texture)
+{
+    struct wined3d_cs_texture_cleanup *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_TEXTURE_CLEANUP;
+    op->texture = texture;
+
+    cs->ops->submit(cs, sizeof(*op));
+}
+
 static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
 {
     /* WINED3D_CS_OP_NOP                        */ wined3d_cs_exec_nop,
@@ -2526,6 +2553,7 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_BUFFER_CLEANUP             */ wined3d_cs_exec_buffer_cleanup,
     /* WINED3D_CS_OP_VOLUME_CLEANUP             */ wined3d_cs_exec_volume_cleanup,
     /* WINED3D_CS_OP_SURFACE_CLEANUP            */ wined3d_cs_exec_surface_cleanup,
+    /* WINED3D_CS_OP_TEXTURE_CLEANUP            */ wined3d_cs_exec_texture_cleanup,
 };
 
 static inline void *_wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, BOOL prio)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index d5cf717..d1386d7 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -104,17 +104,25 @@ static void wined3d_texture_unload_gl_texture(struct wined3d_texture *texture)
     resource_unload(&texture->resource);
 }
 
+void wined3d_texture_cleanup_cs(struct wined3d_texture *texture)
+{
+    wined3d_texture_unload_gl_texture(texture);
+    HeapFree(GetProcessHeap(), 0, texture);
+}
+
 static void wined3d_texture_cleanup(struct wined3d_texture *texture)
 {
     UINT sub_count = texture->level_count * texture->layer_count;
     UINT i;
+    struct wined3d_device *device = texture->resource.device;
 
     TRACE("texture %p.\n", texture);
 
+    /* Because sub_resource_cleanup interferes with GL resources */
     if (wined3d_settings.cs_multithreaded)
     {
         FIXME("Waiting for cs.\n");
-        texture->resource.device->cs->ops->finish(texture->resource.device->cs);
+        device->cs->ops->finish(device->cs);
     }
 
     for (i = 0; i < sub_count; ++i)
@@ -125,10 +133,8 @@ static void wined3d_texture_cleanup(struct wined3d_texture *texture)
             texture->texture_ops->texture_sub_resource_cleanup(sub_resource);
     }
 
-    wined3d_texture_unload_gl_texture(texture);
     resource_cleanup(&texture->resource);
-    if (wined3d_settings.cs_multithreaded)
-        texture->resource.device->cs->ops->finish(texture->resource.device->cs);
+    wined3d_cs_emit_texture_cleanup(device->cs, texture);
 }
 
 void wined3d_texture_set_swapchain(struct wined3d_texture *texture, struct wined3d_swapchain *swapchain)
@@ -414,9 +420,10 @@ ULONG CDECL wined3d_texture_decref(struct wined3d_texture *texture)
 
     if (!refcount)
     {
+        void *parent = texture->resource.parent;
+        const struct wined3d_parent_ops *parent_ops = texture->resource.parent_ops;
         wined3d_texture_cleanup(texture);
-        texture->resource.parent_ops->wined3d_object_destroyed(texture->resource.parent);
-        HeapFree(GetProcessHeap(), 0, texture);
+        parent_ops->wined3d_object_destroyed(parent);
     }
 
     return refcount;
@@ -1025,6 +1032,7 @@ static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3
     if (WINED3DFMT_UNKNOWN >= desc->format)
     {
         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
+        HeapFree(GetProcessHeap(), 0, texture);
         return WINED3DERR_INVALIDCALL;
     }
 
@@ -1055,6 +1063,7 @@ static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3
                 else
                 {
                     WARN("Attempted to create a mipmapped/cube NPOT texture without unconditional NPOT support.\n");
+                    HeapFree(GetProcessHeap(), 0, texture);
                     return WINED3DERR_INVALIDCALL;
                 }
             }
@@ -1067,12 +1076,14 @@ static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3
         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
         {
             WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
+            HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
 
         if (level_count != 1)
         {
             WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning WINED3DERR_INVALIDCALL.\n");
+            HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
     }
@@ -1081,6 +1092,7 @@ static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3
             flags, device, parent, parent_ops, &texture2d_resource_ops)))
     {
         WARN("Failed to initialize texture, returning %#x.\n", hr);
+        HeapFree(GetProcessHeap(), 0, texture);
         return hr;
     }
 
@@ -1284,12 +1296,14 @@ static HRESULT volumetexture_init(struct wined3d_texture *texture, const struct
     if (WINED3DFMT_UNKNOWN >= desc->format)
     {
         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
+        HeapFree(GetProcessHeap(), 0, texture);
         return WINED3DERR_INVALIDCALL;
     }
 
     if (!gl_info->supported[EXT_TEXTURE3D])
     {
         WARN("(%p) : Texture cannot be created - no volume texture support.\n", texture);
+        HeapFree(GetProcessHeap(), 0, texture);
         return WINED3DERR_INVALIDCALL;
     }
 
@@ -1299,12 +1313,14 @@ static HRESULT volumetexture_init(struct wined3d_texture *texture, const struct
         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
         {
             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
+            HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
 
         if (levels != 1)
         {
             WARN("WINED3DUSAGE_AUTOGENMIPMAP is set, and level count != 1, returning D3DERR_INVALIDCALL.\n");
+            HeapFree(GetProcessHeap(), 0, texture);
             return WINED3DERR_INVALIDCALL;
         }
     }
@@ -1332,6 +1348,7 @@ static HRESULT volumetexture_init(struct wined3d_texture *texture, const struct
             {
                 WARN("Attempted to create a NPOT volume texture (%u, %u, %u) without GL support.\n",
                         desc->width, desc->height, desc->depth);
+                HeapFree(GetProcessHeap(), 0, texture);
                 return WINED3DERR_INVALIDCALL;
             }
         }
@@ -1341,6 +1358,7 @@ static HRESULT volumetexture_init(struct wined3d_texture *texture, const struct
             0, device, parent, parent_ops, &texture3d_resource_ops)))
     {
         WARN("Failed to initialize texture, returning %#x.\n", hr);
+        HeapFree(GetProcessHeap(), 0, texture);
         return hr;
     }
 
@@ -1601,7 +1619,6 @@ HRESULT CDECL wined3d_texture_create(struct wined3d_device *device, const struct
     if (FAILED(hr))
     {
         WARN("Failed to initialize texture, returning %#x.\n", hr);
-        HeapFree(GetProcessHeap(), 0, object);
         return hr;
     }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 2e8a82f..f5582dc 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2493,6 +2493,7 @@ static inline struct gl_texture *wined3d_texture_get_gl_texture(struct wined3d_t
 
 void wined3d_texture_apply_sampler_desc(struct wined3d_texture *texture,
         const struct wined3d_sampler_desc *sampler_desc, const struct wined3d_context *context) DECLSPEC_HIDDEN;
+void wined3d_texture_cleanup_cs(struct wined3d_texture *texture) DECLSPEC_HIDDEN;
 void wined3d_texture_bind(struct wined3d_texture *texture,
         struct wined3d_context *context, BOOL srgb) DECLSPEC_HIDDEN;
 void wined3d_texture_bind_and_dirtify(struct wined3d_texture *texture,
@@ -2929,6 +2930,7 @@ void wined3d_cs_emit_resource_cleanup(struct wined3d_cs *cs,
 void wined3d_cs_emit_buffer_cleanup(struct wined3d_cs *cs, struct wined3d_buffer *buffer) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_volume_cleanup(struct wined3d_cs *cs, struct wined3d_volume *volume) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_surface_cleanup(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_texture_cleanup(struct wined3d_cs *cs, struct wined3d_texture *texture) DECLSPEC_HIDDEN;
 
 /* Direct3D terminology with little modifications. We do not have an issued state
  * because only the driver knows about it, but we have a created state because d3d
-- 
2.7.1

