[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