[PATCH 1/3] wined3d: Record dirty regions for d3d9 textures.

Henri Verbeet hverbeet at codeweavers.com
Tue Dec 10 11:56:15 CST 2019


From: Akihiro Sagawa <sagawa.aki at gmail.com>

Signed-off-by: Akihiro Sagawa <sagawa.aki at gmail.com>
Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
This supersedes patches 175193 and 175194.

 dlls/d3d9/texture.c            |  9 ++++-
 dlls/wined3d/device.c          | 19 ++++++++++
 dlls/wined3d/texture.c         | 78 ++++++++++++++++++++++++++++++++++++++----
 dlls/wined3d/wined3d_private.h | 10 ++++++
 include/wine/wined3d.h         |  1 +
 5 files changed, 109 insertions(+), 8 deletions(-)

diff --git a/dlls/d3d9/texture.c b/dlls/d3d9/texture.c
index ae754b5fa2c..2ef27a6de3d 100644
--- a/dlls/d3d9/texture.c
+++ b/dlls/d3d9/texture.c
@@ -1369,6 +1369,8 @@ HRESULT texture_init(struct d3d9_texture *texture, struct d3d9_device *device,
     }
     if (!levels)
         levels = wined3d_log2i(max(width, height)) + 1;
+    if (pool == D3DPOOL_SYSTEMMEM)
+        flags |= WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS;
 
     wined3d_mutex_lock();
     hr = wined3d_texture_create(device->wined3d_device, &desc, 1, levels, flags,
@@ -1449,6 +1451,8 @@ HRESULT cubetexture_init(struct d3d9_texture *texture, struct d3d9_device *devic
     }
     if (!levels)
         levels = wined3d_log2i(edge_length) + 1;
+    if (pool == D3DPOOL_SYSTEMMEM)
+        flags |= WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS;
 
     wined3d_mutex_lock();
     hr = wined3d_texture_create(device->wined3d_device, &desc, 6, levels, flags,
@@ -1470,6 +1474,7 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev
         UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool)
 {
     struct wined3d_resource_desc desc;
+    DWORD flags = 0;
     HRESULT hr;
 
     if (pool == D3DPOOL_MANAGED && device->d3d_parent->extended)
@@ -1513,9 +1518,11 @@ HRESULT volumetexture_init(struct d3d9_texture *texture, struct d3d9_device *dev
     }
     if (!levels)
         levels = wined3d_log2i(max(max(width, height), depth)) + 1;
+    if (pool == D3DPOOL_SYSTEMMEM)
+        flags |= WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS;
 
     wined3d_mutex_lock();
-    hr = wined3d_texture_create(device->wined3d_device, &desc, 1, levels, 0,
+    hr = wined3d_texture_create(device->wined3d_device, &desc, 1, levels, flags,
             NULL, texture, &d3d9_texture_wined3d_parent_ops, &texture->wined3d_texture);
     wined3d_mutex_unlock();
     if (FAILED(hr))
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 0ae841d4e35..dc92d4f4b74 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4059,8 +4059,10 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
 {
     unsigned int src_size, dst_size, src_skip_levels = 0;
     unsigned int src_level_count, dst_level_count;
+    const struct wined3d_dirty_regions *regions;
     unsigned int layer_count, level_count, i, j;
     enum wined3d_resource_type type;
+    BOOL entire_texture = TRUE;
     struct wined3d_box box;
 
     TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
@@ -4127,6 +4129,21 @@ HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
         return WINED3DERR_INVALIDCALL;
     }
 
+    if ((regions = src_texture->dirty_regions))
+    {
+        for (i = 0; i < layer_count && entire_texture; ++i)
+        {
+            if (regions[i].box_count >= WINED3D_MAX_DIRTY_REGION_COUNT)
+                continue;
+
+            entire_texture = FALSE;
+            break;
+        }
+    }
+
+    if (!entire_texture)
+        FIXME("Ignoring dirty regions.\n");
+
     /* Update every surface level of the texture. */
     for (i = 0; i < level_count; ++i)
     {
@@ -4140,6 +4157,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 7c9c8298519..03372504bc6 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -340,6 +340,21 @@ void wined3d_texture_invalidate_location(struct wined3d_texture *texture,
                 sub_resource_idx, texture);
 }
 
+void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture)
+{
+    unsigned int i;
+
+    TRACE("texture %p\n", texture);
+
+    if (!texture->dirty_regions)
+        return;
+
+    for (i = 0; i < texture->layer_count; ++i)
+    {
+        texture->dirty_regions[i].box_count = 0;
+    }
+}
+
 static BOOL wined3d_texture_copy_sysmem_location(struct wined3d_texture *texture,
         unsigned int sub_resource_idx, struct wined3d_context *context, DWORD location)
 {
@@ -1114,6 +1129,15 @@ static void wined3d_texture_destroy_object(void *object)
         heap_free(texture->overlay_info);
     }
 
+    if (texture->dirty_regions)
+    {
+        for (i = 0; i < texture->layer_count; ++i)
+        {
+            heap_free(texture->dirty_regions[i].boxes);
+        }
+        heap_free(texture->dirty_regions);
+    }
+
     resource->resource_ops->resource_unload(resource);
 }
 
@@ -1770,6 +1794,37 @@ static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(str
     return &texture->sub_resources[sub_resource_idx];
 }
 
+static void wined3d_texture_dirty_region_add(struct wined3d_texture *texture,
+        unsigned int layer, const struct wined3d_box *box)
+{
+    struct wined3d_dirty_regions *regions;
+    unsigned int count;
+
+    if (!texture->dirty_regions)
+        return;
+
+    regions = &texture->dirty_regions[layer];
+    count = regions->box_count + 1;
+    if (count >= WINED3D_MAX_DIRTY_REGION_COUNT || !box
+            || (!box->left && !box->top && !box->front
+            && box->right == texture->resource.width
+            && box->bottom == texture->resource.height
+            && box->back == texture->resource.depth))
+    {
+        regions->box_count = WINED3D_MAX_DIRTY_REGION_COUNT;
+        return;
+    }
+
+    if (!wined3d_array_reserve((void **)&regions->boxes, &regions->boxes_size, count, sizeof(*regions->boxes)))
+    {
+        WARN("Failed to grow boxes array, marking entire texture dirty.\n");
+        regions->box_count = WINED3D_MAX_DIRTY_REGION_COUNT;
+        return;
+    }
+
+    regions->boxes[regions->box_count++] = *box;
+}
+
 HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
         UINT layer, const struct wined3d_box *dirty_region)
 {
@@ -1781,16 +1836,13 @@ HRESULT CDECL wined3d_texture_add_dirty_region(struct wined3d_texture *texture,
         return WINED3DERR_INVALIDCALL;
     }
 
-    if (dirty_region)
+    if (dirty_region && FAILED(wined3d_texture_check_box_dimensions(texture, 0, dirty_region)))
     {
-        if (FAILED(wined3d_texture_check_box_dimensions(texture, 0, dirty_region)))
-        {
-            WARN("Invalid dirty_region %s specified.\n", debug_box(dirty_region));
-            return WINED3DERR_INVALIDCALL;
-        }
-        FIXME("Ignoring dirty_region %s.\n", debug_box(dirty_region));
+        WARN("Invalid dirty_region %s specified.\n", debug_box(dirty_region));
+        return WINED3DERR_INVALIDCALL;
     }
 
+    wined3d_texture_dirty_region_add(texture, layer, dirty_region);
     wined3d_cs_emit_add_dirty_texture_region(texture->resource.device->cs, texture, layer);
 
     return WINED3D_OK;
@@ -3090,6 +3142,11 @@ static HRESULT texture_resource_sub_resource_map(struct wined3d_resource *resour
         return E_OUTOFMEMORY;
     }
 
+    /* We only record dirty regions for the top-most level. */
+    if (texture->dirty_regions && flags & WINED3D_MAP_WRITE
+            && !(flags & WINED3D_MAP_NO_DIRTY_UPDATE) && !texture_level)
+        wined3d_texture_dirty_region_add(texture, sub_resource_idx / texture->level_count, box);
+
     if (flags & WINED3D_MAP_WRITE
             && (!(flags & WINED3D_MAP_NO_DIRTY_UPDATE) || (resource->usage & WINED3DUSAGE_DYNAMIC)))
         wined3d_texture_invalidate_location(texture, sub_resource_idx, ~resource->map_binding);
@@ -3382,6 +3439,13 @@ static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struc
             texture->flags |= WINED3D_TEXTURE_GENERATE_MIPMAPS;
     }
 
+    if (flags & WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS
+            && !(texture->dirty_regions = heap_calloc(texture->layer_count, sizeof(*texture->dirty_regions))))
+    {
+        wined3d_texture_cleanup_sync(texture);
+        return E_OUTOFMEMORY;
+    }
+
     /* Precalculated scaling for 'faked' non power of two texture coords. */
     if (texture->resource.gl_type == WINED3D_GL_RES_TYPE_TEX_RECT)
     {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 8f9ad1ce856..60ddf74a0ec 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -74,6 +74,8 @@
 #define WINED3D_QUIRK_BROKEN_ARB_FOG            0x00000200
 #define WINED3D_QUIRK_NO_INDEPENDENT_BIT_DEPTHS 0x00000400
 
+#define WINED3D_MAX_DIRTY_REGION_COUNT 7
+
 struct wined3d_fragment_pipe_ops;
 struct wined3d_adapter;
 struct wined3d_context;
@@ -3538,6 +3540,13 @@ struct wined3d_texture
         DWORD color_key_flags;
     } async;
 
+    struct wined3d_dirty_regions
+    {
+        struct wined3d_box *boxes;
+        SIZE_T boxes_size;
+        unsigned int box_count;
+    } *dirty_regions;
+
     struct wined3d_overlay_info
     {
         struct list entry;
@@ -3666,6 +3675,7 @@ void wined3d_texture_upload_from_texture(struct wined3d_texture *dst_texture, un
         unsigned int src_sub_resource_idx, const struct wined3d_box *src_box) DECLSPEC_HIDDEN;
 void wined3d_texture_validate_location(struct wined3d_texture *texture,
         unsigned int sub_resource_idx, DWORD location) DECLSPEC_HIDDEN;
+void wined3d_texture_clear_dirty_regions(struct wined3d_texture *texture) DECLSPEC_HIDDEN;
 
 HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct wined3d_device *device,
         const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 4b5d4e02f9b..db88e110327 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -1565,6 +1565,7 @@ enum wined3d_shader_type
 #define WINED3D_TEXTURE_CREATE_GET_DC_LENIENT                   0x00000004
 #define WINED3D_TEXTURE_CREATE_GET_DC                           0x00000008
 #define WINED3D_TEXTURE_CREATE_GENERATE_MIPMAPS                 0x00000010
+#define WINED3D_TEXTURE_CREATE_RECORD_DIRTY_REGIONS             0x00000020
 
 #define WINED3D_STANDARD_MULTISAMPLE_PATTERN                    0xffffffff
 
-- 
2.11.0




More information about the wine-devel mailing list