From 2aca1492440a076d00c910b6479b76fe69c1b2ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Thu, 31 Aug 2017 05:04:15 +0200
Subject: [PATCH] d3d11: Implement d3d11_deferred_context_UpdateSubresource.

---
 dlls/d3d11/device.c       | 75 +++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/resource.c   | 93 +++++++++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d.spec |  1 +
 include/wine/wined3d.h    |  2 +
 4 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index c83d6a0..4f3700d 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -45,6 +45,7 @@ enum deferred_cmd
     DEFERRED_COPYRESOURCE,              /* copy_resource_info */
     DEFERRED_SETRESOURCEMINLOD,         /* set_resource_min_lod_info */
     DEFERRED_COPYSUBRESOURCEREGION,     /* copy_subresource_region_info */
+    DEFERRED_UPDATESUBRESOURCE,         /* update_subresource_info */
     DEFERRED_RESOLVESUBRESOURCE,        /* resolve_subresource_info */
     DEFERRED_COPYSTRUCTURECOUNT,        /* copy_structure_count_info */
 
@@ -185,6 +186,15 @@ struct deferred_call
         } copy_subresource_region_info;
         struct
         {
+            ID3D11Resource *resource;
+            UINT subresource_idx;
+            D3D11_BOX *box;
+            void *data;
+            UINT row_pitch;
+            UINT depth_pitch;
+        } update_subresource_info;
+        struct
+        {
             ID3D11Resource *dst_resource;
             UINT dst_subresource_idx;
             ID3D11Resource *src_resource;
@@ -568,6 +578,12 @@ static void free_deferred_calls(struct list *commands)
                     ID3D11Resource_Release(call->copy_subresource_region_info.src_resource);
                 break;
             }
+            case DEFERRED_UPDATESUBRESOURCE:
+            {
+                if (call->update_subresource_info.resource)
+                    ID3D11Resource_Release(call->update_subresource_info.resource);
+                break;
+            }
             case DEFERRED_RESOLVESUBRESOURCE:
             {
                 if (call->resolve_subresource_info.dst_resource)
@@ -899,6 +915,17 @@ static void exec_deferred_calls(ID3D11DeviceContext1 *iface, struct list *comman
                         call->copy_structure_count_info.src_view);
                 break;
             }
+            case DEFERRED_UPDATESUBRESOURCE:
+            {
+                ID3D11DeviceContext1_UpdateSubresource(iface,
+                        call->update_subresource_info.resource,
+                        call->update_subresource_info.subresource_idx,
+                        call->update_subresource_info.box,
+                        call->update_subresource_info.data,
+                        call->update_subresource_info.row_pitch,
+                        call->update_subresource_info.depth_pitch);
+                break;
+            }
             case DEFERRED_CSSETSHADER:
             {
                 ID3D11DeviceContext1_CSSetShader(iface, call->cs_info.shader, NULL, 0);
@@ -5054,8 +5081,54 @@ static void STDMETHODCALLTYPE d3d11_deferred_context_UpdateSubresource(ID3D11Dev
         ID3D11Resource *resource, UINT subresource_idx, const D3D11_BOX *box,
         const void *data, UINT row_pitch, UINT depth_pitch)
 {
-    FIXME("iface %p, resource %p, subresource_idx %u, box %p, data %p, row_pitch %u, depth_pitch %u stub!\n",
+    struct d3d11_deferred_context *context = impl_from_deferred_ID3D11DeviceContext(iface);
+    struct wined3d_resource *wined3d_resource;
+    struct wined3d_box wined3d_box;
+    struct deferred_call *call;
+    UINT size;
+
+    TRACE("iface %p, resource %p, subresource_idx %u, box %p, data %p, row_pitch %u, depth_pitch %u.\n",
             iface, resource, subresource_idx, box, data, row_pitch, depth_pitch);
+
+    if (box)
+        wined3d_box_set(&wined3d_box, box->left, box->top, box->right, box->bottom, box->front, box->back);
+
+    wined3d_resource = wined3d_resource_from_d3d11_resource(resource);
+    wined3d_mutex_lock();
+    size = wined3d_resource_update_info(wined3d_resource, subresource_idx,
+            box ? &wined3d_box : NULL, row_pitch, depth_pitch);
+    wined3d_mutex_unlock();
+
+    if (!size)
+    {
+        FIXME("Failed to calculate size of data\n");
+        return;
+    }
+
+    if (!(call = add_deferred_call(context, size + (box ? sizeof(D3D11_BOX) : 0))))
+        return;
+
+    call->cmd = DEFERRED_UPDATESUBRESOURCE;
+    call->update_subresource_info.resource = resource;
+    call->update_subresource_info.subresource_idx = subresource_idx;
+    call->update_subresource_info.row_pitch = row_pitch;
+    call->update_subresource_info.depth_pitch = depth_pitch;
+
+    ID3D11Resource_AddRef(resource);
+
+    if (box)
+    {
+        call->update_subresource_info.box  = (void *)(call + 1);
+        call->update_subresource_info.data = (void *)(call->update_subresource_info.box + 1);
+        *call->update_subresource_info.box = *box;
+    }
+    else
+    {
+        call->update_subresource_info.box  = NULL;
+        call->update_subresource_info.data = (void *)(call + 1);
+    }
+
+    memcpy(call->update_subresource_info.data, data, size);
 }
 
 static void STDMETHODCALLTYPE d3d11_deferred_context_CopyStructureCount(ID3D11DeviceContext *iface,
diff --git a/dlls/wined3d/resource.c b/dlls/wined3d/resource.c
index 28581a1..c2a9933 100644
--- a/dlls/wined3d/resource.c
+++ b/dlls/wined3d/resource.c
@@ -373,6 +373,99 @@ HRESULT CDECL wined3d_resource_unmap(struct wined3d_resource *resource, unsigned
     return wined3d_cs_unmap(resource->device->cs, resource, sub_resource_idx);
 }
 
+UINT CDECL wined3d_resource_update_info(struct wined3d_resource *resource, unsigned int sub_resource_idx,
+        const struct wined3d_box *box, unsigned int row_pitch, unsigned int depth_pitch)
+{
+    unsigned int width, height, depth;
+    struct wined3d_box b;
+    UINT data_size;
+
+    TRACE("resource %p, sub_resource_idx %u, box %s, row_pitch %u, depth_pitch %u.\n",
+            resource, sub_resource_idx, debug_box(box), row_pitch, depth_pitch);
+
+    if (resource->type == WINED3D_RTYPE_BUFFER)
+    {
+        if (sub_resource_idx > 0)
+        {
+            WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx);
+            return 0;
+        }
+
+        width = resource->size;
+        height = 1;
+        depth = 1;
+    }
+    else if (resource->type == WINED3D_RTYPE_TEXTURE_1D ||
+            resource->type == WINED3D_RTYPE_TEXTURE_2D || resource->type == WINED3D_RTYPE_TEXTURE_3D)
+    {
+        struct wined3d_texture *texture = texture_from_resource(resource);
+        unsigned int level;
+
+        if (sub_resource_idx >= texture->level_count * texture->layer_count)
+        {
+            WARN("Invalid sub_resource_idx %u.\n", sub_resource_idx);
+            return 0;
+        }
+
+        level = sub_resource_idx % texture->level_count;
+        width = wined3d_texture_get_level_width(texture, level);
+        height = wined3d_texture_get_level_height(texture, level);
+        depth = wined3d_texture_get_level_depth(texture, level);
+    }
+    else
+    {
+        FIXME("Not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
+        return 0;
+    }
+
+    if (!box)
+    {
+        wined3d_box_set(&b, 0, 0, width, height, 0, depth);
+        box = &b;
+    }
+    else if (box->left >= box->right || box->right > width
+            || box->top >= box->bottom || box->bottom > height
+            || box->front >= box->back || box->back > depth)
+    {
+        WARN("Invalid box %s specified.\n", debug_box(box));
+        return 0;
+    }
+
+    if (resource->format_flags & WINED3DFMT_FLAG_BLOCKS)
+    {
+        if (resource->type != WINED3D_RTYPE_TEXTURE_2D)
+        {
+            FIXME("Calculation of block formats not implemented for %s resources.\n", debug_d3dresourcetype(resource->type));
+            return 0;
+        }
+
+        height  = (box->bottom - box->top  + resource->format->block_height - 1) / resource->format->block_height;
+        width   = (box->right  - box->left + resource->format->block_width  - 1) / resource->format->block_width;
+        return (height - 1) * row_pitch + width * resource->format->block_byte_count;
+    }
+
+    data_size = 0;
+    switch (resource->type)
+    {
+        case WINED3D_RTYPE_TEXTURE_3D:
+            data_size += (box->back - box->front - 1) * depth_pitch;
+            /* fall-through */
+        case WINED3D_RTYPE_TEXTURE_2D:
+            data_size += (box->bottom - box->top - 1) * row_pitch;
+            /* fall-through */
+        case WINED3D_RTYPE_TEXTURE_1D:
+            data_size += (box->right - box->left) * resource->format->byte_count;
+            break;
+        case WINED3D_RTYPE_BUFFER:
+            data_size = box->right - box->left;
+            break;
+        case WINED3D_RTYPE_NONE:
+            break;
+    }
+
+    return data_size;
+}
+
 void CDECL wined3d_resource_preload(struct wined3d_resource *resource)
 {
     wined3d_cs_emit_preload_resource(resource->device->cs, resource);
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 58dc0a9..fe6e0af 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -234,6 +234,7 @@
 @ cdecl wined3d_resource_set_parent(ptr ptr)
 @ cdecl wined3d_resource_set_priority(ptr long)
 @ cdecl wined3d_resource_unmap(ptr long)
+@ cdecl wined3d_resource_update_info(ptr long ptr long long)
 
 @ cdecl wined3d_rendertarget_view_create(ptr ptr ptr ptr ptr)
 @ cdecl wined3d_rendertarget_view_create_from_sub_resource(ptr long ptr ptr ptr)
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index fa929e5..0adb891 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2597,6 +2597,8 @@ void __cdecl wined3d_resource_preload(struct wined3d_resource *resource);
 void __cdecl wined3d_resource_set_parent(struct wined3d_resource *resource, void *parent);
 DWORD __cdecl wined3d_resource_set_priority(struct wined3d_resource *resource, DWORD priority);
 HRESULT __cdecl wined3d_resource_unmap(struct wined3d_resource *resource, unsigned int sub_resource_idx);
+UINT __cdecl wined3d_resource_update_info(struct wined3d_resource *resource, unsigned int sub_resource_idx,
+        const struct wined3d_box *box, unsigned int row_pitch, unsigned int depth_pitch);
 
 HRESULT __cdecl wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc,
         struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
-- 
1.9.1

