* 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.
This commit is contained in:
Felix Kuehling 2005-01-29 23:26:23 +00:00
parent 9ff3c49ef2
commit 5ff53cb448
4 changed files with 168 additions and 26 deletions

View 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 },

View 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

View 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;
}

View 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