From: Akihiro Sagawa <sagawa.aki@gmail.com>
Subject: [PATCH 3/4] wined3d: Update a part of the texture if dirty regions is tracked.
Message-Id: <20191207191520.EB3B.375B48EC@gmail.com>
Date: Sat, 07 Dec 2019 19:16:09 +0900


Wine-Bugs: https://bugs.winehq.org/show_bug.cgi?id=35205
Signed-off-by: Akihiro Sagawa <sagawa.aki@gmail.com>
---
 dlls/d3d9/tests/visual.c | 12 ++++++------
 dlls/wined3d/device.c    | 49 +++++++++++++++++++++++++++++++++++++++++-------
 dlls/wined3d/texture.c   | 11 ++++-------
 3 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 0a9fb0a..c873370 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -19340,7 +19340,7 @@ static void add_dirty_rect_test(void)
     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
-    todo_wine ok(color_match(color, 0x00ff0000, 1),
+    ok(color_match(color, 0x00ff0000, 1),
             "Expected color 0x00ff0000, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -19353,7 +19353,7 @@ static void add_dirty_rect_test(void)
     ok(SUCCEEDED(hr), "Failed to update texture, hr %#x.\n", hr);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
-    todo_wine ok(color_match(color, 0x00ff0000, 1),
+    ok(color_match(color, 0x00ff0000, 1),
             "Expected color 0x00ff0000, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -19365,7 +19365,7 @@ static void add_dirty_rect_test(void)
     ok(SUCCEEDED(hr), "Failed to update texture, hr %#x.\n", hr);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
-    todo_wine ok(color_match(color, 0x00ff0000, 1),
+    ok(color_match(color, 0x00ff0000, 1),
             "Expected color 0x00ff0000, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -19382,7 +19382,7 @@ static void add_dirty_rect_test(void)
     ok(color_match(color, 0x0000ff00, 1),
             "Expected color 0x0000ff00, got 0x%08x.\n", color);
     color = getPixelColor(device, 1, 1);
-    todo_wine ok(color_match(color, 0x00ff0000, 1),
+    ok(color_match(color, 0x00ff0000, 1),
             "Expected color 0x00ff0000, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -19404,7 +19404,7 @@ static void add_dirty_rect_test(void)
     ok(SUCCEEDED(hr), "Failed to update texture, hr %#x.\n", hr);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
-    todo_wine ok(color_match(color, 0x0000ff00, 1),
+    ok(color_match(color, 0x0000ff00, 1),
             "Expected color 0x0000ff00, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -19416,7 +19416,7 @@ static void add_dirty_rect_test(void)
     ok(SUCCEEDED(hr), "Failed to update texture, hr %#x.\n", hr);
     add_dirty_rect_test_draw(device);
     color = getPixelColor(device, 320, 240);
-    todo_wine ok(color_match(color, 0x0000ff00, 1),
+    ok(color_match(color, 0x0000ff00, 1),
             "Expected color 0x0000ff00, got 0x%08x.\n", color);
     hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 9337ac1..7705a83 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4062,6 +4062,7 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
     unsigned int layer_count, level_count, i, j;
     enum wined3d_resource_type type;
     struct wined3d_box box;
+    BOOL entire_texture = TRUE;
 
     TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
 
@@ -4127,16 +4128,50 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         return WINED3DERR_INVALIDCALL;
     }
 
+    if (src_texture->dirty_regions)
+        for (i = 0; i < layer_count && entire_texture; ++i)
+            if (src_texture->dirty_regions[i].count < MAX_DIRTY_REGION_COUNT)
+                entire_texture = FALSE;
+
     /* Update every surface level of the texture. */
-    for (i = 0; i < level_count; ++i)
+    if (entire_texture)
     {
-        wined3d_texture_get_level_box(dst_texture, i, &box);
-        for (j = 0; j < layer_count; ++j)
+        for (i = 0; i < level_count; ++i)
+        {
+            wined3d_texture_get_level_box(dst_texture, i, &box);
+            for (j = 0; j < layer_count; ++j)
+            {
+                wined3d_cs_emit_blt_sub_resource(device->cs,
+                        &dst_texture->resource, j * dst_level_count + i, &box,
+                        &src_texture->resource, j * src_level_count + i + src_skip_levels, &box,
+                        0, NULL, WINED3D_TEXF_POINT);
+            }
+        }
+    }
+    else
+    {
+        for (i = 0; i < layer_count; ++i)
         {
-            wined3d_cs_emit_blt_sub_resource(device->cs,
-                    &dst_texture->resource, j * dst_level_count + i, &box,
-                    &src_texture->resource, j * src_level_count + i + src_skip_levels, &box,
-                    0, NULL, WINED3D_TEXF_POINT);
+            for (j = 0; j < level_count; ++j)
+            {
+                /* TODO: We could pass an array of boxes here to avoid
+                   multiple context acquisitions for the same resource. */
+                unsigned int k, src_level = j + src_skip_levels;
+                for (k = 0; k < src_texture->dirty_regions[i].count; ++k)
+                {
+                    box = src_texture->dirty_regions[i].box[k];
+                    if (src_level)
+                        wined3d_box_set(&box, box.left >> src_level, box.top >> src_level,
+                                (box.right + (1u << src_level) - 1) >> src_level,
+                                (box.bottom + (1u << src_level) - 1) >> src_level,
+                                box.front >> src_level,
+                                (box.back + (1u << src_level) - 1) >> src_level);
+                    wined3d_cs_emit_blt_sub_resource(device->cs,
+                            &dst_texture->resource, i * dst_level_count + j, &box,
+                            &src_texture->resource, i * src_level_count + src_level, &box,
+                            0, NULL, WINED3D_TEXF_POINT);
+                }
+            }
         }
     }
 
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 1882352..852b934 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1831,14 +1831,11 @@ HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
         return WINED3DERR_INVALIDCALL;
     }
 
-    if (dirty_region)
+    if (dirty_region
+        && FAILED(wined3d_texture_check_box_dimensions(texture, 0, dirty_region)))
     {
-        if (FAILED(wined3d_texture_check_box_dimensions(texture, 0, dirty_region)))
-        {
-            WARN("Invalid dirty_region %s specified.\n", debug_box(dirty_region));
-            return WINED3DERR_INVALIDCALL;
-        }
-        FIXME("Ignoring dirty_region %s.\n", debug_box(dirty_region));
+        WARN("Invalid dirty_region %s specified.\n", debug_box(dirty_region));
+        return WINED3DERR_INVALIDCALL;
     }
 
     wined3d_texture_dirty_region_add(texture, layer, dirty_region);