From a67a9a39ffcf23526dbabc064d02520c41a5ecdb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Thu, 1 Aug 2013 00:33:48 +0200
Subject: wined3d: Send update_texture calls through the CS

---
 dlls/wined3d/cs.c              |  33 ++++++++++++
 dlls/wined3d/device.c          | 119 +++++++++++++++++++----------------------
 dlls/wined3d/wined3d_private.h |   4 ++
 3 files changed, 91 insertions(+), 65 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index f17a222..31f7087 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -73,6 +73,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_UPDATE_SURFACE,
     WINED3D_CS_OP_TEXTURE_PRELOAD,
     WINED3D_CS_OP_SURFACE_PRELOAD,
+    WINED3D_CS_OP_UPDATE_TEXTURE,
     WINED3D_CS_OP_STOP,
 };
 
@@ -413,6 +414,12 @@ struct wined3d_cs_surface_preload
     struct wined3d_surface *surface;
 };
 
+struct wined3d_cs_update_texture
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_texture *src, *dst;
+};
+
 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);
@@ -2002,6 +2009,31 @@ void wined3d_cs_emit_surface_preload(struct wined3d_cs *cs, struct wined3d_surfa
     cs->ops->submit(cs, sizeof(*op));
 }
 
+static UINT wined3d_cs_exec_update_texture(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_update_texture *op = data;
+    struct wined3d_context *context;
+
+    context = context_acquire(cs->device, NULL);
+    device_exec_update_texture(context, op->src, op->dst);
+    context_release(context);
+
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_update_texture(struct wined3d_cs *cs, struct wined3d_texture *src,
+        struct wined3d_texture *dst)
+{
+    struct wined3d_cs_update_texture *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_UPDATE_TEXTURE;
+    op->src = src;
+    op->dst = dst;
+
+    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,
@@ -2053,6 +2085,7 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_UPDATE_SURFACE             */ wined3d_cs_exec_update_surface,
     /* WINED3D_CS_OP_TEXTURE_PRELOAD            */ wined3d_cs_exec_texture_preload,
     /* WINED3D_CS_OP_SURFACE_PRELOAD            */ wined3d_cs_exec_surface_preload,
+    /* WINED3D_CS_OP_UPDATE_TEXTURE             */ wined3d_cs_exec_update_texture,
 };
 
 static inline void *_wined3d_cs_mt_require_space(struct wined3d_cs *cs, size_t size, BOOL prio)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index d302b17..e7c5bcc 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3420,16 +3420,15 @@ void CDECL wined3d_device_draw_indexed_primitive_instanced(struct wined3d_device
 }
 
 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
-static HRESULT device_update_volume(struct wined3d_device *device,
+static HRESULT device_update_volume(struct wined3d_context *context,
         struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
 {
     struct wined3d_const_bo_address data;
     struct wined3d_map_desc src;
     HRESULT hr;
-    struct wined3d_context *context;
 
-    TRACE("device %p, src_volume %p, dst_volume %p.\n",
-            device, src_volume, dst_volume);
+    TRACE("src_volume %p, dst_volume %p.\n",
+            src_volume, dst_volume);
 
     if (src_volume->resource.format != dst_volume->resource.format)
     {
@@ -3447,8 +3446,6 @@ static HRESULT device_update_volume(struct wined3d_device *device,
     if (FAILED(hr = wined3d_volume_map(src_volume, &src, NULL, WINED3D_MAP_READONLY)))
         return hr;
 
-    context = context_acquire(device, NULL);
-
     /* Only a prepare, since we're uploading the entire volume. */
     wined3d_texture_prepare_texture(dst_volume->container, context, FALSE);
     wined3d_texture_bind_and_dirtify(dst_volume->container, context, FALSE);
@@ -3458,48 +3455,17 @@ static HRESULT device_update_volume(struct wined3d_device *device,
     wined3d_volume_upload_data(dst_volume, context, &data);
     wined3d_resource_invalidate_location(&dst_volume->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
 
-    context_release(context);
-
     hr = wined3d_volume_unmap(src_volume);
 
     return hr;
 }
 
-HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
-        struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
+/* Context activation is done by the caller */
+void device_exec_update_texture(struct wined3d_context *context, struct wined3d_texture *src_texture,
+        struct wined3d_texture *dst_texture)
 {
-    enum wined3d_resource_type type;
+    enum wined3d_resource_type type = src_texture->resource.type;
     unsigned int level_count, i, j, src_size, dst_size, src_skip_levels = 0;
-    HRESULT hr;
-    struct wined3d_context *context;
-
-    TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
-
-    /* Verify that the source and destination textures are non-NULL. */
-    if (!src_texture || !dst_texture)
-    {
-        WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
-        return WINED3DERR_INVALIDCALL;
-    }
-
-    if (src_texture->resource.pool != WINED3D_POOL_SYSTEM_MEM)
-    {
-        WARN("Source texture not in WINED3D_POOL_SYSTEM_MEM, returning WINED3DERR_INVALIDCALL.\n");
-        return WINED3DERR_INVALIDCALL;
-    }
-    if (dst_texture->resource.pool != WINED3D_POOL_DEFAULT)
-    {
-        WARN("Destination texture not in WINED3D_POOL_DEFAULT, returning WINED3DERR_INVALIDCALL.\n");
-        return WINED3DERR_INVALIDCALL;
-    }
-
-    /* Verify that the source and destination textures are the same type. */
-    type = src_texture->resource.type;
-    if (dst_texture->resource.type != type)
-    {
-        WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
-        return WINED3DERR_INVALIDCALL;
-    }
 
     level_count = min(wined3d_texture_get_level_count(src_texture),
             wined3d_texture_get_level_count(dst_texture));
@@ -3517,17 +3483,8 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         ++src_skip_levels;
     }
 
-    if (wined3d_settings.cs_multithreaded)
-    {
-        FIXME("Waiting for cs.\n");
-        wined3d_cs_emit_glfinish(device->cs);
-        device->cs->ops->finish(device->cs);
-    }
-
     /* Make sure that the destination texture is loaded. */
-    context = context_acquire(device, NULL);
     wined3d_texture_load(dst_texture, context, FALSE);
-    context_release(context);
 
     /* Update every surface level of the texture. */
     switch (type)
@@ -3542,12 +3499,7 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
                 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture,
                         i + src_skip_levels));
                 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
-                hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to update surface, hr %#x.\n", hr);
-                    return hr;
-                }
+                surface_upload_from_surface(dst_surface, NULL, src_surface, NULL);
             }
             break;
         }
@@ -3567,12 +3519,7 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
                             i * src_levels + j + src_skip_levels));
                     dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture,
                             i * dst_levels + j));
-                    hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
-                    if (FAILED(hr))
-                    {
-                        WARN("Failed to update surface, hr %#x.\n", hr);
-                        return hr;
-                    }
+                    surface_upload_from_surface(dst_surface, NULL, src_surface, NULL);
                 }
             }
             break;
@@ -3582,14 +3529,15 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         {
             for (i = 0; i < level_count; ++i)
             {
-                hr = device_update_volume(device,
+                HRESULT hr;
+                hr = device_update_volume(context,
                         volume_from_resource(wined3d_texture_get_sub_resource(src_texture,
                                 i + src_skip_levels)),
                         volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
                 if (FAILED(hr))
                 {
                     WARN("Failed to update volume, hr %#x.\n", hr);
-                    return hr;
+                    return;
                 }
             }
             break;
@@ -3597,9 +3545,50 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
 
         default:
             FIXME("Unsupported texture type %#x.\n", type);
-            return WINED3DERR_INVALIDCALL;
+            return;
+    }
+}
+
+HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
+        struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
+{
+    enum wined3d_resource_type type;
+
+    TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
+
+    /* Verify that the source and destination textures are non-NULL. */
+    if (!src_texture || !dst_texture)
+    {
+        WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
     }
 
+    if (src_texture->resource.pool != WINED3D_POOL_SYSTEM_MEM)
+    {
+        WARN("Source texture not in WINED3D_POOL_SYSTEM_MEM, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    if (dst_texture->resource.pool != WINED3D_POOL_DEFAULT)
+    {
+        WARN("Destination texture not in WINED3D_POOL_DEFAULT, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+    if (dst_texture->resource.format != src_texture->resource.format)
+    {
+        WARN("Formats do not match, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    /* Verify that the source and destination textures are the same type. */
+    type = src_texture->resource.type;
+    if (dst_texture->resource.type != type)
+    {
+        WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    wined3d_cs_emit_update_texture(device->cs, src_texture, dst_texture);
+
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 3081be5..3297c5e 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2152,6 +2152,8 @@ void device_resource_add(struct wined3d_device *device, struct wined3d_resource
 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 void device_invalidate_state(const struct wined3d_device *device, DWORD state) DECLSPEC_HIDDEN;
 void device_invalidate_shader_constants(const struct wined3d_device *device, DWORD mask) DECLSPEC_HIDDEN;
+void device_exec_update_texture(struct wined3d_context *context, struct wined3d_texture *src_texture,
+        struct wined3d_texture *dst_texture) DECLSPEC_HIDDEN;
 
 static inline BOOL isStateDirty(const struct wined3d_context *context, DWORD state)
 {
@@ -2744,6 +2746,8 @@ void wined3d_cs_emit_update_surface(struct wined3d_cs *cs, struct wined3d_surfac
         const RECT *src_rect, struct wined3d_surface *dst, const POINT *dst_point) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_texture_preload(struct wined3d_cs *cs, struct wined3d_texture *texture) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_surface_preload(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_update_texture(struct wined3d_cs *cs, struct wined3d_texture *src,
+        struct wined3d_texture *dst) 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.5.1

