From 6e0637c6122e1cb792ae028ab60d45b91fb4d3a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20D=C3=B6singer?= <stefan@codeweavers.com>
Date: Fri, 4 Sep 2015 15:22:49 +0200
Subject: wined3d: Send update_sub_resource calls through the command stream.

---
 dlls/wined3d/cs.c              | 91 ++++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c          | 43 +-------------------
 dlls/wined3d/wined3d_private.h |  3 ++
 3 files changed, 95 insertions(+), 42 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 01c4ba3..277291b 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -94,6 +94,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_GETDC,
     WINED3D_CS_OP_RELEASEDC,
     WINED3D_CS_OP_SAMPLER_DESTROY,
+    WINED3D_CS_OP_UPDATE_SUB_RESOURCE,
     WINED3D_CS_OP_STOP,
 };
 
@@ -564,6 +565,15 @@ struct wined3d_cs_sampler_destroy
     struct wined3d_sampler *sampler;
 };
 
+struct wined3d_cs_update_sub_resource
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_resource *resource;
+    unsigned int sub_resource_idx, row_pitch, depth_pitch;
+    const struct wined3d_box *box;
+    const void *data;
+};
+
 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);
@@ -2785,6 +2795,86 @@ void wined3d_cs_emit_sampler_destroy(struct wined3d_cs *cs, struct wined3d_sampl
     cs->ops->submit(cs, sizeof(*op));
 }
 
+static UINT wined3d_cs_exec_update_sub_resource(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_update_sub_resource *op = data;
+
+    struct wined3d_resource *sub_resource;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_const_bo_address addr;
+    struct wined3d_context *context;
+    struct wined3d_texture *texture;
+    struct wined3d_surface *surface;
+    POINT dst_point;
+    RECT src_rect;
+
+    texture = wined3d_texture_from_resource(op->resource);
+    sub_resource = wined3d_texture_get_sub_resource(texture, op->sub_resource_idx);
+    surface = surface_from_resource(sub_resource);
+
+    src_rect.left = 0;
+    src_rect.top = 0;
+    if (op->box)
+    {
+        src_rect.right = op->box->right - op->box->left;
+        src_rect.bottom = op->box->bottom - op->box->top;
+        dst_point.x = op->box->left;
+        dst_point.y = op->box->top;
+    }
+    else
+    {
+        src_rect.right = sub_resource->width;
+        src_rect.bottom = sub_resource->height;
+        dst_point.x = 0;
+        dst_point.y = 0;
+    }
+
+    addr.buffer_object = 0;
+    addr.addr = op->data;
+
+    context = context_acquire(cs->device, NULL);
+    gl_info = context->gl_info;
+
+    /* Only load the surface for partial updates. */
+    if (!dst_point.x && !dst_point.y && src_rect.right == sub_resource->width
+            && src_rect.bottom == sub_resource->height)
+        wined3d_texture_prepare_texture(texture, context, FALSE);
+    else
+        wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
+    wined3d_texture_bind_and_dirtify(texture, context, FALSE);
+
+    wined3d_surface_upload_data(surface, gl_info, op->resource->format,
+            &src_rect, op->row_pitch, &dst_point, FALSE, &addr);
+
+    context_release(context);
+
+    wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
+    wined3d_resource_invalidate_location(&surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
+
+    return sizeof(*op);
+}
+
+void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
+        unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
+        unsigned int depth_pitch)
+{
+    struct wined3d_cs_update_sub_resource *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op));
+    op->opcode = WINED3D_CS_OP_UPDATE_SUB_RESOURCE;
+    op->resource = resource;
+    op->sub_resource_idx = sub_resource_idx;
+    op->box = box;
+    op->data = data;
+    op->row_pitch = row_pitch;
+    op->depth_pitch = depth_pitch;
+
+    cs->ops->submit(cs, sizeof(*op));
+    /* The data pointer may go away, need to wait until the data is read. Copying the data may be faster.
+     * Don't forget to copy box as well in this case. */
+    cs->ops->finish(cs);
+}
+
 static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void *data) =
 {
     /* WINED3D_CS_OP_NOP                        */ wined3d_cs_exec_nop,
@@ -2857,6 +2947,7 @@ static UINT (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_GETDC                      */ wined3d_cs_exec_getdc,
     /* WINED3D_CS_OP_RELEASEDC                  */ wined3d_cs_exec_releasedc,
     /* WINED3D_CS_OP_SAMPLER_DESTROY            */ wined3d_cs_exec_sampler_destroy,
+    /* WINED3D_CS_OP_UPDATE_SUB_RESOURCE        */ wined3d_cs_exec_update_sub_resource,
 };
 
 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 a6766e5..93498d8 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3934,13 +3934,7 @@ void CDECL wined3d_device_update_sub_resource(struct wined3d_device *device, str
         unsigned int depth_pitch)
 {
     struct wined3d_resource *sub_resource;
-    const struct wined3d_gl_info *gl_info;
-    struct wined3d_const_bo_address addr;
-    struct wined3d_context *context;
     struct wined3d_texture *texture;
-    struct wined3d_surface *surface;
-    POINT dst_point;
-    RECT src_rect;
 
     TRACE("device %p, resource %p, sub_resource_idx %u, box %p, data %p, row_pitch %u, depth_pitch %u.\n",
             device, resource, sub_resource_idx, box, data, row_pitch, depth_pitch);
@@ -3957,10 +3951,7 @@ void CDECL wined3d_device_update_sub_resource(struct wined3d_device *device, str
         WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx);
         return;
     }
-    surface = surface_from_resource(sub_resource);
 
-    src_rect.left = 0;
-    src_rect.top = 0;
     if (box)
     {
         if (box->left >= box->right || box->right > sub_resource->width
@@ -3970,41 +3961,9 @@ void CDECL wined3d_device_update_sub_resource(struct wined3d_device *device, str
                     box->left, box->top, box->front, box->right, box->bottom, box->back);
             return;
         }
-
-        src_rect.right = box->right - box->left;
-        src_rect.bottom = box->bottom - box->top;
-        dst_point.x = box->left;
-        dst_point.y = box->top;
     }
-    else
-    {
-        src_rect.right = sub_resource->width;
-        src_rect.bottom = sub_resource->height;
-        dst_point.x = 0;
-        dst_point.y = 0;
-    }
-
-    addr.buffer_object = 0;
-    addr.addr = data;
-
-    context = context_acquire(resource->device, NULL);
-    gl_info = context->gl_info;
-
-    /* Only load the surface for partial updates. */
-    if (!dst_point.x && !dst_point.y && src_rect.right == sub_resource->width
-            && src_rect.bottom == sub_resource->height)
-        wined3d_texture_prepare_texture(texture, context, FALSE);
-    else
-        wined3d_resource_load_location(&surface->resource, context, WINED3D_LOCATION_TEXTURE_RGB);
-    wined3d_texture_bind_and_dirtify(texture, context, FALSE);
-
-    wined3d_surface_upload_data(surface, gl_info, resource->format,
-            &src_rect, row_pitch, &dst_point, FALSE, &addr);
-
-    context_release(context);
 
-    wined3d_resource_validate_location(&surface->resource, WINED3D_LOCATION_TEXTURE_RGB);
-    wined3d_resource_invalidate_location(&surface->resource, ~WINED3D_LOCATION_TEXTURE_RGB);
+    wined3d_cs_emit_update_sub_resource(device->cs, resource, sub_resource_idx, box, data, row_pitch, depth_pitch);
 }
 
 HRESULT CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9125336..d9dd839 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2823,6 +2823,9 @@ void wined3d_cs_emit_delete_opengl_contexts(struct wined3d_cs *cs,
 void wined3d_cs_emit_getdc(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_releasedc(struct wined3d_cs *cs, struct wined3d_surface *surface) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_sampler_destroy(struct wined3d_cs *cs, struct wined3d_sampler *sampler) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_update_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *resource,
+        unsigned int sub_resource_idx, const struct wined3d_box *box, const void *data, unsigned int row_pitch,
+        unsigned int depth_pitch) 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

