* Fixed uploading of textures of certain sizes.
authorFelix Kuehling <fxkuehl@gmx.de>
Sat, 29 Jan 2005 23:26:23 +0000 (23:26 +0000)
committerFelix Kuehling <fxkuehl@gmx.de>
Sat, 29 Jan 2005 23:26:23 +0000 (23:26 +0000)
* 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
src/mesa/drivers/dri/savage/savagecontext.h
src/mesa/drivers/dri/savage/savagetex.c
src/mesa/drivers/dri/savage/savagetex.h

index 2c31aefce11963d7836f94c9a2f69807129137bd..171cbde90ef4a52d91a361da6f949a1e04d35b34 100644 (file)
@@ -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 },
index 21385ed7ec493635aa34d34c94895dbe977305d0..b2d47a469398201c2935985b241e2b8d444c5e27 100644 (file)
@@ -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
index e6954a048ab4c39936a3847be552f1320de2d3b1..fd8bd0d1258cae86e67b80bd8b08bc52d2c01423 100644 (file)
@@ -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;
 }
 
index a6732a3dce7f289715205daa99e8e88eb163c790..f08903739099b5f6136303fdd9d2232516b12e4f 100644 (file)
@@ -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