mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-15 16:00:20 +01:00
* 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:
parent
9ff3c49ef2
commit
5ff53cb448
4 changed files with 168 additions and 26 deletions
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue