From: Masanori Kakura Subject: [v6 PATCH 2/3] wined3d: Add dirty region tracking. Message-Id: <20170528141047.24496-2-kakurasan@gmail.com> Date: Sun, 28 May 2017 23:10:46 +0900 In-Reply-To: <20170528141047.24496-1-kakurasan@gmail.com> References: <20170528141047.24496-1-kakurasan@gmail.com> 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 v6 - Fix issue when clearing regions - Add TRACE()s Signed-off-by: Masanori Kakura --- dlls/d3d8/tests/visual.c | 10 ++-- dlls/d3d9/tests/visual.c | 10 ++-- dlls/wined3d/cs.c | 60 ++++++++++++++++++++- dlls/wined3d/texture.c | 117 +++++++++++++++++++++++++++++++++++++++-- dlls/wined3d/wined3d_private.h | 12 ++++- 5 files changed, 193 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 d86657e2f2..0132894cd9 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,6 +2190,13 @@ 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; + + /* 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_resource; /* Update every surface level of the texture. */ for (i = 0; i < level_count; ++i) @@ -2284,6 +2293,10 @@ static void wined3d_cs_exec_update_texture(struct wined3d_cs *cs, const void *da } } + for (i = 0; i < src_texture->layer_count; ++i) + wined3d_texture_clear_dirty_regions(src_texture, i); + +release_resource: wined3d_resource_release(&src_texture->resource); wined3d_resource_release(&dst_texture->resource); } @@ -2318,6 +2331,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; @@ -2328,13 +2342,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; @@ -2342,6 +2397,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 476295cecc..e520979c90 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -385,6 +385,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; } @@ -911,6 +920,10 @@ static void wined3d_texture_cleanup_sync(struct wined3d_texture *texture) static void wined3d_texture_destroy_object(void *object) { + UINT i; + + for (i = 0; i < ((struct wined3d_texture *)object)->layer_count; ++i) + wined3d_texture_clear_dirty_regions(object, i); wined3d_texture_cleanup(object); HeapFree(GetProcessHeap(), 0, object); } @@ -1604,10 +1617,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; } @@ -1916,7 +1927,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); @@ -3104,3 +3148,68 @@ 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) +{ + TRACE("texture %p, layer %u, region (%u, %u, %u)-(%u, %u, %u).\n", + texture, layer, left, top, front, right, bottom, 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) + { + TRACE("Reuse region %s.\n", debug_box(box)); + 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) +{ + TRACE("texture %p, layer %u.\n", texture, layer); + + wined3d_texture_clear_dirty_regions(texture, layer); + + 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 layer) +{ + TRACE("texture %p, layer %u.\n", texture, layer); + + if (texture->async.dirty_regions_count[layer] > 0) + HeapFree(GetProcessHeap(), 0, texture->async.dirty_regions[layer]); + + texture->async.dirty_regions_size[layer] = texture->async.dirty_regions_count[layer] = 0; +} diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index b4f4e8bafb..7ba1c2f839 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3004,6 +3004,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 @@ -3094,6 +3099,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, UINT layer) DECLSPEC_HIDDEN; #define WINED3D_LOCATION_DISCARDED 0x00000001 #define WINED3D_LOCATION_SYSMEM 0x00000002 @@ -3367,7 +3376,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