From 5ff53cb448aa8dcf752ceaa9eb47a7c8a9c3ab0c Mon Sep 17 00:00:00 2001
From: Felix Kuehling <fxkuehl@gmx.de>
Date: Sat, 29 Jan 2005 23:26:23 +0000
Subject: * Fixed uploading of textures of certain sizes. * When
 glTexSubImageND is used, track the set of changed tiles in a   bit vector and
 upload only dirty tiles later. This should improve   the performance of
 dynamic light maps and gl movie player plugins. * Renamed debug item "lru" to
 "tex". Indicate which levels are   uploaded completely or partially.

---
 src/mesa/drivers/dri/savage/savage_xmesa.c  |   2 +-
 src/mesa/drivers/dri/savage/savagecontext.h |   2 +-
 src/mesa/drivers/dri/savage/savagetex.c     | 186 ++++++++++++++++++++++++----
 src/mesa/drivers/dri/savage/savagetex.h     |   4 +-
 4 files changed, 168 insertions(+), 26 deletions(-)

(limited to 'src/mesa')

diff --git a/src/mesa/drivers/dri/savage/savage_xmesa.c b/src/mesa/drivers/dri/savage/savage_xmesa.c
index 2c31aefce11..171cbde90ef 100644
--- a/src/mesa/drivers/dri/savage/savage_xmesa.c
+++ b/src/mesa/drivers/dri/savage/savage_xmesa.c
@@ -100,7 +100,7 @@ static const struct dri_debug_control debug_control[] =
 {
     { "fall",  DEBUG_FALLBACKS },
     { "api",   DEBUG_VERBOSE_API },
-    { "lru",   DEBUG_VERBOSE_LRU },
+    { "tex",   DEBUG_VERBOSE_TEX },
     { "verb",  DEBUG_VERBOSE_MSG },
     { "dma",   DEBUG_DMA },
     { "state", DEBUG_STATE },
diff --git a/src/mesa/drivers/dri/savage/savagecontext.h b/src/mesa/drivers/dri/savage/savagecontext.h
index 21385ed7ec4..b2d47a46939 100644
--- a/src/mesa/drivers/dri/savage/savagecontext.h
+++ b/src/mesa/drivers/dri/savage/savagecontext.h
@@ -313,7 +313,7 @@ extern int SAVAGE_DEBUG;
 
 #define DEBUG_FALLBACKS      0x001
 #define DEBUG_VERBOSE_API    0x002
-#define DEBUG_VERBOSE_LRU    0x004
+#define DEBUG_VERBOSE_TEX    0x004
 #define DEBUG_VERBOSE_MSG    0x008
 #define DEBUG_DMA            0x010
 #define DEBUG_STATE          0x020
diff --git a/src/mesa/drivers/dri/savage/savagetex.c b/src/mesa/drivers/dri/savage/savagetex.c
index e6954a048ab..fd8bd0d1258 100644
--- a/src/mesa/drivers/dri/savage/savagetex.c
+++ b/src/mesa/drivers/dri/savage/savagetex.c
@@ -203,6 +203,9 @@ static void savageUploadTexLevel( savageTexObjPtr t, int level )
 		 (int) image->Border);
 
     if (width >= 8 && height >= tileInfo->subHeight) {
+	GLuint *dirtyPtr = t->image[level].dirtyTiles;
+	GLuint dirtyMask = 1;
+
 	if (width >= tileInfo->width && height >= tileInfo->height) {
 	    GLuint wInTiles = width / tileInfo->width;
 	    GLuint hInTiles = height / tileInfo->height;
@@ -212,14 +215,41 @@ static void savageUploadTexLevel( savageTexObjPtr t, int level )
 	    for (y = 0; y < hInTiles; ++y) {
 		src = srcTRow;
 		for (x = 0; x < wInTiles; ++x) {
-		    savageUploadTile (tileInfo,
-				      tileInfo->wInSub, tileInfo->hInSub, bpp,
-				      src, width * bpp, dest);
+		    if (*dirtyPtr & dirtyMask) {
+			savageUploadTile (tileInfo,
+					  tileInfo->wInSub, tileInfo->hInSub,
+					  bpp, src, width * bpp, dest);
+		    }
 		    src += tileInfo->width * bpp;
 		    dest += 2048; /* tile size is always 2k */
+		    if (dirtyMask == 1<<31) {
+			dirtyMask = 1;
+			dirtyPtr++;
+		    } else
+			dirtyMask <<= 1;
 		}
 		srcTRow += width * tileInfo->height * bpp;
 	    }
+	} else if (width >= tileInfo->width) {
+	    GLuint wInTiles = width / tileInfo->width;
+	    GLubyte *src = image->Data;
+	    GLubyte *dest = (GLubyte *)(t->bufAddr + t->image[level].offset);
+	    GLuint x;
+	    for (x = 0; x < wInTiles; ++x) {
+		if (*dirtyPtr & dirtyMask) {
+		    savageUploadTile (tileInfo,
+				      tileInfo->wInSub,
+				      height / tileInfo->subHeight,
+				      bpp, src, width * bpp, dest);
+		}
+		src += tileInfo->width * bpp;
+		dest += 2048; /* tile size is always 2k */
+		if (dirtyMask == 1<<31) {
+		    dirtyMask = 1;
+		    dirtyPtr++;
+		} else
+		    dirtyMask <<= 1;
+	    }
 	} else {
 	    savageUploadTile (tileInfo, width / tileInfo->subWidth,
 			      height / tileInfo->subHeight, bpp,
@@ -270,6 +300,67 @@ static GLuint savageTexImageSize (GLuint width, GLuint height, GLuint bpp) {
 	return 64 * bpp;
 }
 
+/** \brief Compute the number of (partial) tiles of a texture image
+ */
+static GLuint savageTexImageTiles (GLuint width, GLuint height,
+				   const savageTileInfo *tileInfo)
+{
+   return (width + tileInfo->width - 1) / tileInfo->width *
+      (height + tileInfo->height - 1) / tileInfo->height;
+}
+
+/** \brief Mark dirty tiles
+ *
+ * Some care must be taken because tileInfo may not be set or not
+ * up-to-date. So we check if tileInfo is initialized and if the number
+ * of tiles in the bit vector matches the number of tiles computed from
+ * the current tileInfo.
+ */
+static void savageMarkDirtyTiles (savageTexObjPtr t, GLuint level,
+				  GLuint totalWidth, GLuint totalHeight,
+				  GLint xoffset, GLint yoffset,
+				  GLsizei width, GLsizei height)
+{
+   GLuint wInTiles, hInTiles;
+   GLuint x0, y0, x1, y1;
+   GLuint x, y;
+   if (!t->tileInfo)
+      return;
+   wInTiles = (totalWidth + t->tileInfo->width - 1) / t->tileInfo->width;
+   hInTiles = (totalHeight + t->tileInfo->height - 1) / t->tileInfo->height;
+   if (wInTiles * hInTiles != t->image[level].nTiles)
+      return;
+
+   x0 = xoffset / t->tileInfo->width;
+   y0 = yoffset / t->tileInfo->height;
+   x1 = (xoffset + width - 1) / t->tileInfo->width;
+   y1 = (yoffset + height - 1) / t->tileInfo->height;
+
+   for (y = y0; y <= y1; ++y) {
+      GLuint *ptr = t->image[level].dirtyTiles + (y * wInTiles + x0) / 32;
+      GLuint mask = 1 << (y * wInTiles + x0) % 32;
+      for (x = x0; x <= x1; ++x) {
+	 *ptr |= mask;
+	 if (mask == (1<<31)) {
+	    ptr++;
+	    mask = 1;
+	 } else {
+	    mask <<= 1;
+	 }
+      }
+   }
+}
+
+/** \brief Mark all tiles as dirty
+ */
+static void savageMarkAllTiles (savageTexObjPtr t, GLuint level)
+{
+   GLuint words = (t->image[level].nTiles + 31) / 32;
+   if (words)
+      memset(t->image[level].dirtyTiles, ~0, words*sizeof(GLuint));
+}
+
+
 static void savageSetTexWrapping(savageTexObjPtr tex, GLenum s, GLenum t)
 {
     tex->setup.sWrapMode = s;
@@ -301,10 +392,19 @@ savageAllocTexObj( struct gl_texture_object *texObj )
    t = (savageTexObjPtr) calloc(1,sizeof(*t));
    texObj->DriverData = t;
    if ( t != NULL ) {
+      GLuint i;
 
       /* Initialize non-image-dependent parts of the state:
        */
       t->base.tObj = texObj;
+      t->base.dirty_images[0] = 0;
+      t->dirtySubImages = 0;
+      t->tileInfo = NULL;
+
+      /* Initialize dirty tiles bit vectors
+       */
+      for (i = 0; i < SAVAGE_TEX_MAXLEVELS; ++i)
+	 t->image[i].nTiles = 0;
 
       /* FIXME Something here to set initial values for other parts of
        * FIXME t->setup?
@@ -521,12 +621,27 @@ static void savageSetTexImages( savageContextPtr imesa,
    firstLevel = t->base.firstLevel;
    lastLevel  = t->base.lastLevel;
 
-   /* Figure out the size now (and count the levels).  Upload won't be done
-    * until later.
+   /* Figure out the size now (and count the levels).  Upload won't be
+    * done until later. If the number of tiles changes, it means that
+    * this function is called for the first time on this tex object or
+    * the image or the destination color format changed. So all tiles
+    * are marked as dirty.
     */ 
    offset = 0;
    size = 1;
    for ( i = firstLevel ; i <= lastLevel && tObj->Image[0][i] ; i++ ) {
+      GLuint nTiles;
+      nTiles = savageTexImageTiles (image->Width2, image->Height2, t->tileInfo);
+      if (t->image[i].nTiles != nTiles) {
+	 GLuint words = (nTiles + 31) / 32;
+	 if (t->image[i].nTiles != 0) {
+	    free(t->image[i].dirtyTiles);
+	 }
+	 t->image[i].dirtyTiles = malloc(words*sizeof(GLuint));
+	 memset(t->image[i].dirtyTiles, ~0, words*sizeof(GLuint));
+      }
+      t->image[i].nTiles = nTiles;
+
       t->image[i].offset = offset;
 
       image = tObj->Image[0][i];
@@ -545,18 +660,24 @@ static void savageSetTexImages( savageContextPtr imesa,
    t->base.totalSize = (t->base.totalSize + 2047UL) & ~2047UL;
 }
 
-void savageDestroyTexObj(savageContextPtr imesa, driTextureObject *t)
+void savageDestroyTexObj(savageContextPtr imesa, savageTexObjPtr t)
 {
+    GLuint i;
+
+    /* Free dirty tiles bit vectors */
+    for (i = 0; i < SAVAGE_TEX_MAXLEVELS; ++i) {
+	if (t->image[i].nTiles)
+	    free (t->image[i].dirtyTiles);
+    }
+
     /* See if it was the driver's current object.
      */
-
     if ( imesa != NULL )
     { 
-	GLuint i;
 	for ( i = 0 ; i < imesa->glCtx->Const.MaxTextureUnits ; i++ )
 	{
-	    if ( t == imesa->CurrentTexObj[ i ] ) {
-		assert( t->bound & (1 << i) );
+	    if ( &t->base == imesa->CurrentTexObj[ i ] ) {
+		assert( t->base.bound & (1 << i) );
 		imesa->CurrentTexObj[ i ] = NULL;
 	    }
 	}
@@ -600,21 +721,36 @@ static void savageUploadTexImages( savageContextPtr imesa, savageTexObjPtr t )
    driUpdateTextureLRU( &t->base );
    UNLOCK_HARDWARE(imesa);
 
-   if (t->base.dirty_images[0]) {
+   if (t->base.dirty_images[0] || t->dirtySubImages) {
+      if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX)
+	 fprintf(stderr, "Texture upload: |");
+
       savageFlushVertices (imesa);
       LOCK_HARDWARE(imesa);
       savageFlushCmdBufLocked (imesa, GL_FALSE);
       WAIT_IDLE_EMPTY_LOCKED(imesa);
-      if (SAVAGE_DEBUG & DEBUG_VERBOSE_LRU)
-	 fprintf(stderr, "*");
 
       for (i = 0 ; i < numLevels ; i++) {
          const GLint j = t->base.firstLevel + i;  /* the texObj's level */
-	 if (t->base.dirty_images[0] & (1<<j))
+	 if (t->base.dirty_images[0] & (1 << j)) {
+	    savageMarkAllTiles(t, j);
+	    if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX)
+		fprintf (stderr, "*");
+	 } else if ((SAVAGE_DEBUG & DEBUG_VERBOSE_TEX) &&
+		    t->dirtySubImages & (1 << j))
+	    fprintf (stderr, ".");
+	 else
+	    fprintf (stderr, " ");
+	 if ((t->base.dirty_images[0] | t->dirtySubImages) & (1 << j))
 	    savageUploadTexLevel( t, j );
       }
+
       UNLOCK_HARDWARE(imesa);
       t->base.dirty_images[0] = 0;
+      t->dirtySubImages = 0;
+
+      if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX)
+	 fprintf(stderr, "|\n");
    }
 }
 
@@ -657,7 +793,7 @@ static void savageUpdateTex0State_s4( GLcontext *ctx )
    imesa->CurrentTexObj[0] = &t->base;
    t->base.bound |= 1;
 
-   if (t->base.dirty_images[0]) {
+   if (t->base.dirty_images[0] || t->dirtySubImages) {
        savageSetTexImages(imesa, tObj);
        savageUploadTexImages(imesa, t); 
    }
@@ -924,7 +1060,7 @@ static void savageUpdateTex1State_s4( GLcontext *ctx )
 
    t->base.bound |= 2;
 
-   if (t->base.dirty_images[0]) {
+   if (t->base.dirty_images[0] || t->dirtySubImages) {
        savageSetTexImages(imesa, tObj);
        savageUploadTexImages(imesa, t);
    }
@@ -1112,7 +1248,7 @@ static void savageUpdateTexState_s3d( GLcontext *ctx )
     imesa->CurrentTexObj[0] = &t->base;
     t->base.bound |= 1;
 
-    if (t->base.dirty_images[0]) {
+    if (t->base.dirty_images[0] || t->dirtySubImages) {
 	savageSetTexImages(imesa, tObj);
 	savageUploadTexImages(imesa, t);
     }
@@ -1292,7 +1428,7 @@ static void savageTexImage1D( GLcontext *ctx, GLenum target, GLint level,
 {
    savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
    if (t) {
-      driSwapOutTextureObject( &t->base );
+      /* Do nothing. Marking the image as dirty below is sufficient. */
    } else {
       t = savageAllocTexObj(texObj);
       if (!t) {
@@ -1321,18 +1457,20 @@ static void savageTexSubImage1D( GLcontext *ctx,
    savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
    assert( t ); /* this _should_ be true */
    if (t) {
-      driSwapOutTextureObject( &t->base );
+      savageMarkDirtyTiles(t, level, texImage->Width2, 1,
+			   xoffset, 0, width, 1);
    } else {
       t = savageAllocTexObj(texObj);
       if (!t) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
          return;
       }
+      t->base.dirty_images[0] |= (1 << level);
    }
    _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, 
 			     format, type, pixels, packing, texObj,
 			     texImage);
-   t->base.dirty_images[0] |= (1 << level);
+   t->dirtySubImages |= (1 << level);
    SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
 }
 
@@ -1346,7 +1484,7 @@ static void savageTexImage2D( GLcontext *ctx, GLenum target, GLint level,
 {
    savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
    if (t) {
-      driSwapOutTextureObject( &t->base );
+      /* Do nothing. Marking the image as dirty below is sufficient. */
    } else {
       t = savageAllocTexObj(texObj);
       if (!t) {
@@ -1375,18 +1513,20 @@ static void savageTexSubImage2D( GLcontext *ctx,
    savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
    assert( t ); /* this _should_ be true */
    if (t) {
-      driSwapOutTextureObject( &t->base );
+      savageMarkDirtyTiles(t, level, texImage->Width2, texImage->Height2,
+			   xoffset, yoffset, width, height);
    } else {
       t = savageAllocTexObj(texObj);
       if (!t) {
          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
          return;
       }
+      t->base.dirty_images[0] |= (1 << level);
    }
    _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, 
 			     height, format, type, pixels, packing, texObj,
 			     texImage);
-   t->base.dirty_images[0] |= (1 << level);
+   t->dirtySubImages |= (1 << level);
    SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
 }
 
diff --git a/src/mesa/drivers/dri/savage/savagetex.h b/src/mesa/drivers/dri/savage/savagetex.h
index a6732a3dce7..f0890373909 100644
--- a/src/mesa/drivers/dri/savage/savagetex.h
+++ b/src/mesa/drivers/dri/savage/savagetex.h
@@ -43,6 +43,7 @@ typedef struct savage_tileinfo_t {
 
 typedef struct {
     GLuint offset;
+    GLuint nTiles;
     GLuint *dirtyTiles;		/* bit vector of dirty tiles (still unused) */
 } savageTexImage;
 
@@ -53,6 +54,7 @@ typedef struct {
 
     GLuint age;
     savageTexImage image[SAVAGE_TEX_MAXLEVELS];
+    GLuint dirtySubImages;
 
     struct {
 	GLuint sWrapMode, tWrapMode;
@@ -76,6 +78,6 @@ typedef struct {
 void savageUpdateTextureState( GLcontext *ctx );
 void savageDDInitTextureFuncs( struct dd_function_table *functions );
 
-void savageDestroyTexObj( savageContextPtr imesa, driTextureObject *t );
+void savageDestroyTexObj( savageContextPtr imesa, savageTexObjPtr t );
 
 #endif
-- 
cgit v1.2.3