(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;
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,
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;
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?
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];
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;
}
}
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");
}
}
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);
}
t->base.bound |= 2;
- if (t->base.dirty_images[0]) {
+ if (t->base.dirty_images[0] || t->dirtySubImages) {
savageSetTexImages(imesa, tObj);
savageUploadTexImages(imesa, t);
}
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);
}
{
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) {
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;
}
{
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) {
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;
}