[v5 PATCH 2/3] wined3d: Add dirty region tracking.

Masanori Kakura kakurasan at gmail.com
Wed May 24 08:49:56 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()
v4 - Record/use target layer
v5 - Don't access regions in wined3d_device_update_texture()
   - Pass dirty_region to wined3d_cs_exec_add_dirty_texture_region() correctly
   - Record regions per each layer separately

Still no interactions with resource location management.

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              |  59 +++++++++++++++++++++-
 dlls/wined3d/texture.c         | 110 +++++++++++++++++++++++++++++++++++++++--
 dlls/wined3d/wined3d_private.h |  12 ++++-
 5 files changed, 185 insertions(+), 16 deletions(-)

diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c
index 5ff96d4070..b074d9c661 100644
--- a/dlls/d3d8/tests/visual.c
+++ b/dlls/d3d8/tests/visual.c
@@ -5341,7 +5341,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);
@@ -5354,7 +5354,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);
@@ -5366,7 +5366,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);
@@ -5405,7 +5405,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);
@@ -5417,7 +5417,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 c8a6a1fa5a..a23ba32a20 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -17462,7 +17462,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);
@@ -17475,7 +17475,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);
@@ -17487,7 +17487,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);
@@ -17526,7 +17526,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);
@@ -17538,7 +17538,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 bacca09131..53465ed411 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -422,6 +422,8 @@ struct wined3d_cs_add_dirty_texture_region
     enum wined3d_cs_op opcode;
     struct wined3d_texture *texture;
     unsigned int layer;
+    struct wined3d_box dirty_region;
+    BOOL maximize;
 };
 
 struct wined3d_cs_clear_unordered_access_view
@@ -2188,8 +2190,15 @@ static void wined3d_cs_exec_update_texture(struct wined3d_cs *cs, const void *da
     unsigned int src_skip_levels = op->src_skip_levels;
     unsigned int i, j;
     unsigned int width, height, depth;
+    UINT src_dirty_layers = 0;
     struct wined3d_box box;
 
+    /* If there are no dirty regions in the source texture, nothing to update. */
+    for (i = 0; i < layer_count; ++i)
+        src_dirty_layers += src_texture->async.dirty_regions_count[i];
+    if (src_dirty_layers == 0)
+        goto release;
+
     /* Update every surface level of the texture. */
     for (i = 0; i < level_count; ++i)
     {
@@ -2207,6 +2216,9 @@ static void wined3d_cs_exec_update_texture(struct wined3d_cs *cs, const void *da
         }
     }
 
+    wined3d_texture_clear_dirty_regions(src_texture);
+
+release:
     wined3d_resource_release(&src_texture->resource);
     wined3d_resource_release(&dst_texture->resource);
 }
@@ -2241,6 +2253,7 @@ static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, cons
     struct wined3d_texture *texture = op->texture;
     unsigned int sub_resource_idx, i;
     struct wined3d_context *context;
+    BOOL maximize = op->maximize;
 
     context = context_acquire(cs->device, NULL, 0);
     sub_resource_idx = op->layer * texture->level_count;
@@ -2251,13 +2264,54 @@ static void wined3d_cs_exec_add_dirty_texture_region(struct wined3d_cs *cs, cons
         else
             ERR("Failed to load location %s.\n", wined3d_debug_location(texture->resource.map_binding));
     }
+
+    if (maximize)
+    {
+        if (!wined3d_texture_maximize_dirty_region(texture, op->layer))
+        {
+            ERR("Failed to allocate memory.\n");
+            goto release;
+        }
+    }
+    else
+    {
+        const struct wined3d_box *dirty_region = &op->dirty_region;
+
+        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 (dirty_region->right > wined3d_texture_get_level_width(texture, 0)
+                || dirty_region->bottom > wined3d_texture_get_level_height(texture, 0)
+                || dirty_region->back > wined3d_texture_get_level_depth(texture, 0))
+        {
+            WARN("Dirty region out of bounds.\n");
+            goto release;
+        }
+
+        if (!wined3d_texture_append_dirty_region(texture, op->layer,
+                                                 dirty_region->left, dirty_region->top,
+                                                 dirty_region->right, dirty_region->bottom,
+                                                 dirty_region->front, dirty_region->back))
+        {
+            ERR("Failed to allocate memory.\n");
+            goto release;
+        }
+    }
+
+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, BOOL maximize)
 {
     struct wined3d_cs_add_dirty_texture_region *op;
 
@@ -2265,6 +2319,9 @@ 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;
+    if (!maximize)
+        op->dirty_region = *dirty_region;
+    op->maximize = maximize;
 
     wined3d_resource_acquire(&texture->resource);
 
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 61be9a2519..32f667a8a3 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -383,6 +383,15 @@ static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struc
     if (flags & WINED3D_TEXTURE_CREATE_DISCARD)
         texture->flags |= WINED3D_TEXTURE_DISCARD;
 
+    for (i = 0; i < layer_count; ++i)
+    {
+        if (!wined3d_texture_maximize_dirty_region(texture, i))
+        {
+            ERR("Failed to allocate memory.\n");
+            return E_OUTOFMEMORY;
+        }
+    }
+
     return WINED3D_OK;
 }
 
@@ -909,6 +918,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);
 }
@@ -1602,10 +1612,8 @@ 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, (dirty_region == NULL) ? TRUE : FALSE);
 
     return WINED3D_OK;
 }
@@ -1914,7 +1922,40 @@ 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 (texture_level == 0)
+        {
+            UINT layer = (sub_resource_idx - texture_level) / texture->level_count;
+            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, layer,
+                                                         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, layer))
+                {
+                    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 = context_map_bo_address(context, &data, sub_resource->size, GL_PIXEL_UNPACK_BUFFER, flags);
@@ -3102,3 +3143,64 @@ 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 layer, UINT left, UINT top, UINT right, UINT bottom, UINT front, UINT back)
+{
+    if (texture->async.dirty_regions_count[layer] == 0)
+    {
+        if (!(texture->async.dirty_regions[layer] = HeapAlloc(GetProcessHeap(), 0, sizeof(*texture->async.dirty_regions[layer]))))
+            return FALSE;
+    }
+    else
+    {
+        UINT i;
+
+        for (i = 0; i < texture->async.dirty_regions_count[layer]; ++i)
+        {
+            const struct wined3d_box *box = &texture->async.dirty_regions[layer][i];
+
+            if (box->left <= left
+                    && box->top <= top
+                    && box->front <= front
+                    && box->right >= right
+                    && box->bottom >= bottom
+                    && box->back >= back)
+            {
+                /* Reuse the region */
+                return TRUE;
+            }
+        }
+
+        if (!wined3d_array_reserve((void **)&texture->async.dirty_regions[layer], &texture->async.dirty_regions_size[layer],
+                texture->async.dirty_regions_count[layer] + 1, sizeof(*texture->async.dirty_regions[layer])))
+            return FALSE;
+    }
+
+    wined3d_box_set(&texture->async.dirty_regions[layer][texture->async.dirty_regions_count[layer]],
+                    left, top, right, bottom, front, back);
+    ++texture->async.dirty_regions_count[layer];
+
+    return TRUE;
+}
+
+BOOL wined3d_texture_maximize_dirty_region(struct wined3d_texture *texture, UINT layer)
+{
+    wined3d_texture_clear_dirty_regions(texture);
+
+    return wined3d_texture_append_dirty_region(texture, layer,
+        0, 0, texture->resource.width, texture->resource.height, 0, texture->resource.depth);
+}
+
+void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture)
+{
+    UINT i;
+
+    for (i = 0; i < texture->layer_count; ++i)
+    {
+        if (texture->async.dirty_regions_count[i] > 0)
+            HeapFree(GetProcessHeap(), 0, texture->async.dirty_regions[i]);
+
+        texture->async.dirty_regions_size[i] = texture->async.dirty_regions_count[i] = 0;
+    }
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 5c830a24c0..612ce58253 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2971,6 +2971,11 @@ struct wined3d_texture
         struct wined3d_color_key src_overlay_color_key;
         struct wined3d_color_key gl_color_key;
         DWORD color_key_flags;
+
+        /* Dirty regions */
+        struct wined3d_box *dirty_regions[6];
+        SIZE_T dirty_regions_size[6];
+        UINT dirty_regions_count[6];
     } async;
 
     struct wined3d_texture_sub_resource
@@ -3061,6 +3066,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 layer, UINT left, UINT top, UINT right, UINT bottom, UINT front, UINT back) DECLSPEC_HIDDEN;
+BOOL wined3d_texture_maximize_dirty_region(struct wined3d_texture *texture, UINT layer) DECLSPEC_HIDDEN;
+void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture) DECLSPEC_HIDDEN;
 
 #define WINED3D_LOCATION_DISCARDED      0x00000001
 #define WINED3D_LOCATION_SYSMEM         0x00000002
@@ -3334,7 +3343,8 @@ 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, BOOL maximize) 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