st/nine: Rewrite Managed texture uploads
authorAxel Davy <axel.davy@ens.fr>
Thu, 19 Feb 2015 18:34:02 +0000 (19:34 +0100)
committerAxel Davy <axel.davy@ens.fr>
Wed, 29 Apr 2015 06:28:11 +0000 (08:28 +0200)
That part of the code was quite obscure.
This new implementation tries to make it clearer
by separating the differents parts, and commenting more.

Signed-off-by: Axel Davy <axel.davy@ens.fr>
src/gallium/state_trackers/nine/basetexture9.c

index 9b7976c3862c5f19efadf223ece21d3366022151..330827aec3759d4d9feec4120a266657ddd4fdbe 100644 (file)
@@ -163,7 +163,8 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
 {
     HRESULT hr;
     unsigned last_level = This->base.info.last_level;
-    unsigned l;
+    unsigned l, min_level_dirty = This->managed.lod;
+    BOOL update_lod;
 
     DBG("This=%p dirty=%i type=%s\n", This, This->managed.dirty,
         nine_D3DRTYPE_to_str(This->base.type));
@@ -173,7 +174,14 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
     if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
         last_level = 0; /* TODO: What if level 0 is not resident ? */
 
-    if (This->managed.lod_resident != This->managed.lod) {
+    update_lod = This->managed.lod_resident != This->managed.lod;
+    if (!update_lod && !This->managed.dirty)
+        return D3D_OK;
+
+    /* Allocate a new resource with the correct number of levels,
+     * Mark states for update, and tell the nine surfaces/volumes
+     * their new resource. */
+    if (update_lod) {
         struct pipe_resource *res;
 
         DBG("updating LOD from %u to %u ...\n", This->managed.lod_resident, This->managed.lod);
@@ -192,148 +200,169 @@ NineBaseTexture9_UploadSelf( struct NineBaseTexture9 *This )
                 state->changed.group |= NINE_STATE_TEXTURE;
         }
 
+        /* Allocate a new resource */
         hr = NineBaseTexture9_CreatePipeResource(This, This->managed.lod_resident != -1);
         if (FAILED(hr))
             return hr;
         res = This->base.resource;
 
-        if (This->managed.lod_resident == -1) /* no levels were resident */
+        if (This->managed.lod_resident == -1) {/* no levels were resident */
+            This->managed.dirty = FALSE; /* We are going to upload everything. */
             This->managed.lod_resident = This->base.info.last_level + 1;
+        }
+
+        if (This->base.type == D3DRTYPE_TEXTURE) {
+            struct NineTexture9 *tex = NineTexture9(This);
+
+            /* last content (if apply) has been copied to the new resource.
+             * Note: We cannot render to surfaces of managed textures.
+             * Note2: the level argument passed is to get the level offset
+             * right when the texture is uploaded (the texture first level
+             * corresponds to This->managed.lod).
+             * Note3: We don't care about the value passed for the surfaces
+             * before This->managed.lod, negative with this implementation. */
+            for (l = 0; l <= This->base.info.last_level; ++l)
+                NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod);
+        } else
+        if (This->base.type == D3DRTYPE_CUBETEXTURE) {
+            struct NineCubeTexture9 *tex = NineCubeTexture9(This);
+            unsigned z;
+
+            for (l = 0; l <= This->base.info.last_level; ++l) {
+                for (z = 0; z < 6; ++z)
+                    NineSurface9_SetResource(tex->surfaces[l * 6 + z],
+                                             res, l - This->managed.lod);
+            }
+        } else
+        if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
+            struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
+
+            for (l = 0; l <= This->base.info.last_level; ++l)
+                NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod);
+        } else {
+            assert(!"invalid texture type");
+        }
+
+        /* We are going to fully upload the new levels,
+         * no need to update dirty parts of the texture for these */
+        min_level_dirty = MAX2(This->managed.lod, This->managed.lod_resident);
+    }
+
+    /* Update dirty parts of the texture */
+    if (This->managed.dirty) {
+        if (This->base.type == D3DRTYPE_TEXTURE) {
+            struct NineTexture9 *tex = NineTexture9(This);
+            struct pipe_box box;
+            box.z = 0;
+            box.depth = 1;
+
+            DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n",
+                tex->dirty_rect.x, tex->dirty_rect.y,
+                tex->dirty_rect.width, tex->dirty_rect.height);
+
+            /* Note: for l < min_level_dirty, the resource is
+             * either non-existing (and thus will be entirely re-uploaded
+             * if the lod changes) or going to have a full upload */
+            if (tex->dirty_rect.width) {
+                for (l = min_level_dirty; l <= last_level; ++l) {
+                    u_box_minify_2d(&box, &tex->dirty_rect, l);
+                    NineSurface9_UploadSelf(tex->surfaces[l], &box);
+                }
+                memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect));
+                tex->dirty_rect.depth = 1;
+            }
+        } else
+        if (This->base.type == D3DRTYPE_CUBETEXTURE) {
+            struct NineCubeTexture9 *tex = NineCubeTexture9(This);
+            unsigned z;
+            struct pipe_box box;
+            box.z = 0;
+            box.depth = 1;
+
+            for (z = 0; z < 6; ++z) {
+                DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z,
+                    tex->dirty_rect[z].x, tex->dirty_rect[z].y,
+                    tex->dirty_rect[z].width, tex->dirty_rect[z].height);
+
+                if (tex->dirty_rect[z].width) {
+                    for (l = min_level_dirty; l <= last_level; ++l) {
+                        u_box_minify_2d(&box, &tex->dirty_rect[z], l);
+                        NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);
+                    }
+                    memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z]));
+                    tex->dirty_rect[z].depth = 1;
+                }
+            }
+        } else
+        if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
+            struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
+            struct pipe_box box;
+
+            DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n",
+                tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y,
+                tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth);
+
+            if (tex->dirty_box.width) {
+                for (l = 0; l <= last_level; ++l) {
+                    u_box_minify_2d(&box, &tex->dirty_box, l);
+                    NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box);
+                }
+                memset(&tex->dirty_box, 0, sizeof(tex->dirty_box));
+            }
+            for (l = min_level_dirty; l <= last_level; ++l)
+                NineVolume9_UploadSelf(tex->volumes[l]);
+        } else {
+            assert(!"invalid texture type");
+        }
+        This->managed.dirty = FALSE;
+    }
 
+    /* Upload the new levels */
+    if (update_lod) {
         if (This->base.type == D3DRTYPE_TEXTURE) {
             struct NineTexture9 *tex = NineTexture9(This);
             struct pipe_box box;
 
-            /* Mark uninitialized levels as dirty. */
             box.x = box.y = box.z = 0;
             box.depth = 1;
             for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
                 box.width = u_minify(This->base.info.width0, l);
                 box.height = u_minify(This->base.info.height0, l);
-                NineSurface9_AddDirtyRect(tex->surfaces[l], &box);
+                NineSurface9_UploadSelf(tex->surfaces[l], &box);
             }
-            for (l = 0; l < This->managed.lod; ++l)
-                NineSurface9_SetResource(tex->surfaces[l], NULL, -1);
-            for (; l <= This->base.info.last_level; ++l)
-                NineSurface9_SetResource(tex->surfaces[l], res, l - This->managed.lod);
         } else
         if (This->base.type == D3DRTYPE_CUBETEXTURE) {
             struct NineCubeTexture9 *tex = NineCubeTexture9(This);
             struct pipe_box box;
             unsigned z;
 
-            /* Mark uninitialized levels as dirty. */
             box.x = box.y = box.z = 0;
             box.depth = 1;
             for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
                 box.width = u_minify(This->base.info.width0, l);
                 box.height = u_minify(This->base.info.height0, l);
                 for (z = 0; z < 6; ++z)
-                    NineSurface9_AddDirtyRect(tex->surfaces[l * 6 + z], &box);
-            }
-            for (l = 0; l < This->managed.lod; ++l) {
-                for (z = 0; z < 6; ++z)
-                    NineSurface9_SetResource(tex->surfaces[l * 6 + z],
-                                             NULL, -1);
-            }
-            for (; l <= This->base.info.last_level; ++l) {
-                for (z = 0; z < 6; ++z)
-                    NineSurface9_SetResource(tex->surfaces[l * 6 + z],
-                                             res, l - This->managed.lod);
+                    NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);
             }
         } else
         if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
             struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
             struct pipe_box box;
 
-            /* Mark uninitialized levels as dirty. */
             box.x = box.y = box.z = 0;
             for (l = This->managed.lod; l < This->managed.lod_resident; ++l) {
                 box.width = u_minify(This->base.info.width0, l);
                 box.height = u_minify(This->base.info.height0, l);
                 box.depth = u_minify(This->base.info.depth0, l);
                 NineVolume9_AddDirtyRegion(tex->volumes[l], &box);
+                NineVolume9_UploadSelf(tex->volumes[l]);
             }
-            for (l = 0; l < This->managed.lod; ++l)
-                NineVolume9_SetResource(tex->volumes[l], NULL, -1);
-            for (; l <= This->base.info.last_level; ++l)
-                NineVolume9_SetResource(tex->volumes[l], res, l - This->managed.lod);
         } else {
             assert(!"invalid texture type");
         }
 
-        if (This->managed.lod < This->managed.lod_resident)
-            This->managed.dirty = TRUE;
         This->managed.lod_resident = This->managed.lod;
     }
-    if (!This->managed.dirty)
-        return D3D_OK;
-
-    if (This->base.type == D3DRTYPE_TEXTURE) {
-        struct NineTexture9 *tex = NineTexture9(This);
-        struct pipe_box box;
-        box.z = 0;
-        box.depth = 1;
-
-        DBG("TEXTURE: dirty rect=(%u,%u) (%ux%u)\n",
-            tex->dirty_rect.x, tex->dirty_rect.y,
-            tex->dirty_rect.width, tex->dirty_rect.height);
-
-        /* Note: for l < This->managed.lod, the resource is
-         * non-existing, and thus will be entirely re-uploaded
-         * if This->managed.lod changes */
-        if (tex->dirty_rect.width) {
-            for (l = This->managed.lod; l <= last_level; ++l) {
-                u_box_minify_2d(&box, &tex->dirty_rect, l);
-                NineSurface9_UploadSelf(tex->surfaces[l], &box);
-            }
-            memset(&tex->dirty_rect, 0, sizeof(tex->dirty_rect));
-            tex->dirty_rect.depth = 1;
-        }
-    } else
-    if (This->base.type == D3DRTYPE_CUBETEXTURE) {
-        struct NineCubeTexture9 *tex = NineCubeTexture9(This);
-        unsigned z;
-        struct pipe_box box;
-        box.z = 0;
-        box.depth = 1;
-
-        for (z = 0; z < 6; ++z) {
-            DBG("FACE[%u]: dirty rect=(%u,%u) (%ux%u)\n", z,
-                tex->dirty_rect[z].x, tex->dirty_rect[z].y,
-                tex->dirty_rect[z].width, tex->dirty_rect[z].height);
-
-            if (tex->dirty_rect[z].width) {
-                for (l = This->managed.lod; l <= last_level; ++l) {
-                    u_box_minify_2d(&box, &tex->dirty_rect[z], l);
-                    NineSurface9_UploadSelf(tex->surfaces[l * 6 + z], &box);
-                }
-                memset(&tex->dirty_rect[z], 0, sizeof(tex->dirty_rect[z]));
-                tex->dirty_rect[z].depth = 1;
-            }
-        }
-    } else
-    if (This->base.type == D3DRTYPE_VOLUMETEXTURE) {
-        struct NineVolumeTexture9 *tex = NineVolumeTexture9(This);
-        struct pipe_box box;
-
-        DBG("VOLUME: dirty_box=(%u,%u,%u) (%ux%ux%u)\n",
-            tex->dirty_box.x, tex->dirty_box.y, tex->dirty_box.y,
-            tex->dirty_box.width, tex->dirty_box.height, tex->dirty_box.depth);
-
-        if (tex->dirty_box.width) {
-            for (l = 0; l <= last_level; ++l) {
-                u_box_minify_2d(&box, &tex->dirty_box, l);
-                NineVolume9_AddDirtyRegion(tex->volumes[l], &tex->dirty_box);
-            }
-            memset(&tex->dirty_box, 0, sizeof(tex->dirty_box));
-        }
-        for (l = This->managed.lod; l <= last_level; ++l)
-            NineVolume9_UploadSelf(tex->volumes[l]);
-    } else {
-        assert(!"invalid texture type");
-    }
-    This->managed.dirty = FALSE;
 
     if (This->base.usage & D3DUSAGE_AUTOGENMIPMAP)
         This->dirty_mip = TRUE;