[v3 PATCH 1/2] wined3d: Add dirty region tracking.

Masanori Kakura kakurasan at gmail.com
Thu Apr 20 09:01:44 CDT 2017


v2 - Use array
   - Regions are stored in struct wined3d_texture
   - Reuse old region if possible
v3 - Update Wine d3d8 test
   - Get rid of "Ignoring dirty_region" FIXME in wined3d_texture_add_dirty_region()

Signed-off-by: Masanori Kakura <kakurasan at gmail.com>
---
 dlls/d3d8/tests/visual.c       | 10 ++---
 dlls/d3d9/tests/visual.c       | 10 ++---
 dlls/wined3d/cs.c              | 51 +++++++++++++++++++++-
 dlls/wined3d/device.c          |  6 +++
 dlls/wined3d/texture.c         | 97 ++++++++++++++++++++++++++++++++++++++++--
 dlls/wined3d/wined3d_private.h |  9 +++-
 6 files changed, 167 insertions(+), 16 deletions(-)

diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c
index 4f0c3975bc..f309430b2a 100644
--- a/dlls/d3d8/tests/visual.c
+++ b/dlls/d3d8/tests/visual.c
@@ -5310,7 +5310,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 = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -5323,7 +5323,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 = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -5335,7 +5335,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 = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -5374,7 +5374,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 = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
@@ -5386,7 +5386,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 = IDirect3DDevice8_Present(device, NULL, NULL, NULL, NULL);
     ok(SUCCEEDED(hr), "Failed to present, hr %#x.\n", hr);
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index db29c3fddf..547494baf1 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -17432,7 +17432,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);
@@ -17445,7 +17445,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);
@@ -17457,7 +17457,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);
@@ -17496,7 +17496,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);
@@ -17508,7 +17508,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/cs.c b/dlls/wined3d/cs.c
index 43352eb7cb..429f06e258 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -407,6 +407,7 @@ struct wined3d_cs_add_dirty_texture_region
     enum wined3d_cs_op opcode;
     struct wined3d_texture *texture;
     unsigned int layer;
+    const struct wined3d_box *dirty_region;
 };
 
 struct wined3d_cs_stop
@@ -2132,17 +2133,64 @@ static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, cons
     for (i = 0; i < texture->level_count; ++i, ++sub_resource_idx)
     {
         if (wined3d_texture_load_location(texture, sub_resource_idx, context, texture->resource.map_binding))
+        {
+            if (sub_resource_idx == 0)
+            {
+                const struct wined3d_box *dirty_region = op->dirty_region;
+
+                if (dirty_region)
+                {
+                    UINT right = dirty_region->right;
+                    UINT bottom = dirty_region->bottom;
+                    UINT back = dirty_region->back;
+
+                    if (dirty_region->left >= dirty_region->right
+                            || dirty_region->top >= dirty_region->bottom
+                            || dirty_region->front >= dirty_region->back)
+                    {
+                        WARN("Empty dirty region specified.\n");
+                        goto release;
+                    }
+
+                    if (right > wined3d_texture_get_level_width(texture, 0)
+                            || bottom > wined3d_texture_get_level_height(texture, 0)
+                            || back > wined3d_texture_get_level_depth(texture, 0))
+                    {
+                        WARN("Dirty region out of bounds.\n");
+                        goto release;
+                    }
+
+                    if (!wined3d_texture_append_dirty_region(texture,
+                                                             dirty_region->left, dirty_region->top,
+                                                             right, bottom,
+                                                             dirty_region->front, back))
+                    {
+                        ERR("Failed to allocate memory.\n");
+                        goto release;
+                    }
+                }
+                else
+                {
+                    if (!wined3d_texture_maximize_dirty_region(texture))
+                    {
+                        ERR("Failed to allocate memory.\n");
+                        goto release;
+                    }
+                }
+            }
             wined3d_texture_invalidate_location(texture, sub_resource_idx, ~texture->resource.map_binding);
+        }
         else
             ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
     }
+release:
     context_release(context);
 
     wined3d_resource_release(&texture->resource);
 }
 
 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
-        struct wined3d_texture *texture, unsigned int layer)
+        struct wined3d_texture *texture, unsigned int layer, const struct wined3d_box *dirty_region)
 {
     struct wined3d_cs_add_dirty_texture_region *op;
 
@@ -2150,6 +2198,7 @@ void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
     op->opcode = WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION;
     op->texture = texture;
     op->layer = layer;
+    op->dirty_region = dirty_region;
 
     wined3d_resource_acquire(&texture->resource);
 
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 7e90be55c4..7b37fb91c2 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3582,6 +3582,10 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         return WINED3DERR_INVALIDCALL;
     }
 
+    /* If there are no dirty regions in the source texture, nothing to update. */
+    if (src_texture->dirty_regions_count == 0)
+        return WINED3D_OK;
+
     src_level_count = src_texture->level_count;
     dst_level_count = dst_texture->level_count;
     level_count = min(src_level_count, dst_level_count);
@@ -3624,6 +3628,8 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         }
     }
 
+    wined3d_texture_clear_dirty_regions(src_texture);
+
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 2419616731..5a337b4612 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -424,6 +424,12 @@ static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struc
     if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
         texture->flags |= WINED3D_TEXTURE_DISCARD;
 
+    if (!wined3d_texture_maximize_dirty_region(texture))
+    {
+        ERR("Failed to allocate memory.\n");
+        return E_OUTOFMEMORY;
+    }
+
     return WINED3D_OK;
 }
 
@@ -950,6 +956,7 @@ static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture)
 
 static void wined3d_texture_destroy_object(void *object)
 {
+    wined3d_texture_clear_dirty_regions(object);
     wined3d_texture_cleanup(object);
     HeapFree(GetProcessHeap(), 0, object);
 }
@@ -1647,10 +1654,7 @@ HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
         return WINED3DERR_INVALIDCALL;
     }
 
-    if (dirty_region)
-        FIXME("Ignoring dirty_region %s.\n", debug_box(dirty_region));
-
-    wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer);
+    wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer, dirty_region);
 
     return WINED3D_OK;
 }
@@ -1963,7 +1967,39 @@ static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resour
 
     if (!(flags & WINED3D_MAP_READONLY)
             && (!(flags & WINED3D_MAP_NO_DIRTY_UPDATE) || (resource->usage & WINED3DUSAGE_DYNAMIC)))
+    {
+        if (sub_resource_idx == 0)
+        {
+            UINT width = wined3d_texture_get_level_width(texture, 0);
+            UINT height = wined3d_texture_get_level_height(texture, 0);
+            UINT depth = wined3d_texture_get_level_depth(texture, 0);
+
+            if (box)
+            {
+                if (!wined3d_texture_append_dirty_region(texture,
+                                                         box->left, box->top,
+                                                         min(width, box->right), min(height, box->bottom),
+                                                         box->front, min(depth, box->back)))
+                {
+                    ERR("Failed to allocate memory.\n");
+                    if (context)
+                        context_release(context);
+                    return E_OUTOFMEMORY;
+                }
+            }
+            else
+            {
+                if (!wined3d_texture_maximize_dirty_region(texture))
+                {
+                    ERR("Failed to allocate memory.\n");
+                    if (context)
+                        context_release(context);
+                    return E_OUTOFMEMORY;
+                }
+            }
+        }
         wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding);
+    }
 
     wined3d_texture_get_memory(texture, sub_resource_idx, &data, resource->map_binding);
     base_memory = wined3d_texture_map_bo_address(&data, sub_resource->size,
@@ -3149,3 +3185,56 @@ HRESULT CDECL wined3d_texture_release_dc(struct wined3d_texture *texture, unsign
 
     return WINED3D_OK;
 }
+
+BOOL wined3d_texture_append_dirty_region(struct wined3d_texture *texture,
+        UINT left, UINT top, UINT right, UINT bottom, UINT front, UINT back)
+{
+    if (texture->dirty_regions_count == 0)
+    {
+        if (!(texture->dirty_regions = HeapAlloc(GetProcessHeap(), 0, sizeof(*texture->dirty_regions))))
+            return FALSE;
+    }
+    else
+    {
+        UINT i;
+
+        for (i = 0; i < texture->dirty_regions_count; ++i)
+        {
+            if (texture->dirty_regions[i].left <= left
+                    && texture->dirty_regions[i].top <= top
+                    && texture->dirty_regions[i].front <= front
+                    && texture->dirty_regions[i].right >= right
+                    && texture->dirty_regions[i].bottom >= bottom
+                    && texture->dirty_regions[i].back >= back)
+            {
+                /* Reuse the region */
+                return TRUE;
+            }
+        }
+
+        if (!wined3d_array_reserve((void **)&texture->dirty_regions, &texture->dirty_regions_size,
+                texture->dirty_regions_count + 1, sizeof(*texture->dirty_regions)))
+            return FALSE;
+    }
+
+    wined3d_box_set(&texture->dirty_regions[texture->dirty_regions_count],
+                    left, top, right, bottom, front, back);
+    ++texture->dirty_regions_count;
+
+    return TRUE;
+}
+
+BOOL wined3d_texture_maximize_dirty_region(struct wined3d_texture *texture)
+{
+    wined3d_texture_clear_dirty_regions(texture);
+
+    return wined3d_texture_append_dirty_region(texture,
+        0, 0, texture->resource.width, texture->resource.height, 0, texture->resource.depth);
+}
+
+void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture)
+{
+    if (texture->dirty_regions_count > 0)
+        HeapFree(GetProcessHeap(), 0, texture->dirty_regions);
+    texture->dirty_regions_size = texture->dirty_regions_count = 0;
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index cd90eb8a41..f56c2763c9 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2902,6 +2902,9 @@ struct wined3d_texture
     unsigned int row_pitch;
     unsigned int slice_pitch;
 
+    struct wined3d_box *dirty_regions;
+    SIZE_T dirty_regions_size, dirty_regions_count;
+
     /* May only be accessed from the command stream worker thread. */
     struct wined3d_texture_async
     {
@@ -3008,6 +3011,10 @@ void wined3d_texture_upload_data(struct wined3d_texture *texture, unsigned int s
         const struct wined3d_const_bo_address *data, unsigned int row_pitch, unsigned int slice_pitch) DECLSPEC_HIDDEN;
 void wined3d_texture_validate_location(struct wined3d_texture *texture,
         unsigned int sub_resource_idx, DWORD location) DECLSPEC_HIDDEN;
+BOOL wined3d_texture_append_dirty_region(struct wined3d_texture *texture,
+        UINT left, UINT top, UINT right, UINT bottom, UINT front, UINT back) DECLSPEC_HIDDEN;
+BOOL wined3d_texture_maximize_dirty_region(struct wined3d_texture *texture) DECLSPEC_HIDDEN;
+void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture) DECLSPEC_HIDDEN;
 
 #define WINED3D_LOCATION_DISCARDED      0x00000001
 #define WINED3D_LOCATION_SYSMEM         0x00000002
@@ -3270,7 +3277,7 @@ void wined3d_cs_destroy(struct wined3d_cs *cs) DECLSPEC_HIDDEN;
 void wined3d_cs_destroy_object(struct wined3d_cs *cs,
         void (*callback)(void *object), void *object) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_add_dirty_texture_region(struct wined3d_cs *cs,
-        struct wined3d_texture *texture, unsigned int layer) DECLSPEC_HIDDEN;
+        struct wined3d_texture *texture, unsigned int layer, const struct wined3d_box *dirty_region) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_blt_sub_resource(struct wined3d_cs *cs, struct wined3d_resource *dst_resource,
         unsigned int dst_sub_resource_idx, const struct wined3d_box *dst_box, struct wined3d_resource *src_resource,
         unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
-- 
2.11.0




More information about the wine-patches mailing list