[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