Attached is a patch to the texmem branch with the changes we've been discussing. I'd still like to take a closer look at the global heap, but I've included the code to force initializing the global heap on the first lock contention for now. I've changed the drm/ddx/texmem code to use the drmTextureRegion/drm_tex_region_t struct for the SAREA and heap structures, but only for the drivers converted to the texmem interface. I also added a test to driAllocateTexture that deletes a placeholder (using t->tObj == NULL to detect a placeholder) instead of swapping it out. An explicit flag for detecting a placeholder might make the code more clear, but using t->tObj should work too. Since placeholders should never be on the swapped list now, I left in the assert for the swapped list being empty in the drivers' DestroyContext, though I added code to delete anything on the swapped list in driDestroyTextureHeap just in case that assertion would need to be removed for some reason.
I've also included the optimization in driTexturesGone to keep an existing placeholder if the global region is in use and matches the size and offset of the existing placeholder. It this looks OK, I will apply it to the branch. I need to do some more testing on the Rage 128 driver, but so far things seem to be working except for the problem in the fire Mesa demo, which is still there. It kind of looks like a texture coordinate problem, but I'm not sure yet. -- Leif Delgass http://www.retinalburn.net
Index: lib/GL/mesa/src/drv/common/texmem.c =================================================================== RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/common/Attic/texmem.c,v retrieving revision 1.1.2.8 diff -u -r1.1.2.8 texmem.c --- lib/GL/mesa/src/drv/common/texmem.c 27 Jan 2003 23:43:31 -0000 1.1.2.8 +++ lib/GL/mesa/src/drv/common/texmem.c 1 Feb 2003 21:39:55 -0000 @@ -119,12 +119,10 @@ static void resetGlobalLRU( driTexHeap * heap ) { - driTexRegion * list = heap->global_regions; + drmTextureRegionPtr list = heap->global_regions; unsigned sz = 1U << heap->logGranularity; unsigned i; - heap->local_age = ++heap->global_age[0]; - for (i = 0 ; (i+1) * sz <= heap->size ; i++) { list[i].prev = i-1; list[i].next = i+1; @@ -140,7 +138,74 @@ heap->global_age[0] = 0; } +/** + * Print out debugging information about the local texture LRU. + * + * \param heap Texture heap to be printed + */ +static void printLocalLRU( driTexHeap * heap ) +{ + driTextureObject *t; + unsigned sz = 1U << heap->logGranularity; + fprintf( stderr, "Local LRU, heap %d:\n", heap->heapId ); + + foreach ( t, &heap->texture_objects ) { + if (!t->memBlock) + continue; + if (!t->tObj) { + fprintf( stderr, "Placeholder (%p) %d at 0x%x sz 0x%x\n", + t, + t->memBlock->ofs / sz, + t->memBlock->ofs, + t->memBlock->size ); + } else { + fprintf( stderr, "Texture (%p) at 0x%x sz 0x%x\n", + t, + t->memBlock->ofs, + t->memBlock->size ); + } + } + foreach ( t, heap->swapped_objects ) { + if (!t->tObj) { + fprintf( stderr, "Swapped Placeholder (%p)\n", t ); + } else { + fprintf( stderr, "Swapped Texture (%p)\n", t ); + } + } + + fprintf( stderr, "\n" ); +} + +/** + * Print out debugging information about the global texture LRU. + * + * \param heap Texture heap to be printed + */ +static void printGlobalLRU( driTexHeap * heap ) +{ + drmTextureRegionPtr list = heap->global_regions; + int i, j; + + fprintf( stderr, "Global LRU, heap %d list %p:\n", heap->heapId, list ); + + for ( i = 0, j = heap->nrRegions ; i < heap->nrRegions ; i++ ) { + fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n", + j, list[j].age, list[j].next, list[j].prev, list[j].in_use ); + j = list[j].next; + if ( j == heap->nrRegions ) break; + } + + if ( j != heap->nrRegions ) { + fprintf( stderr, "Loop detected in global LRU\n" ); + for ( i = 0 ; i < heap->nrRegions ; i++ ) { + fprintf( stderr, "list[%d] age %d next %d prev %d in_use %d\n", + i, list[i].age, list[i].next, list[i].prev, list[i].in_use ); + } + } + + fprintf( stderr, "\n" ); +} /** @@ -152,7 +217,7 @@ void driUpdateTextureLRU( driTextureObject * t ) { driTexHeap * heap; - driTexRegion * list; + drmTextureRegionPtr list; unsigned shift; unsigned start; unsigned end; @@ -194,6 +259,12 @@ list[(unsigned)list[heap->nrRegions].next].prev = i; list[heap->nrRegions].next = i; } + + if ( 0 ) { + printGlobalLRU( heap ); + printLocalLRU( heap ); + } + } } @@ -326,7 +397,13 @@ } else { - driDestroyTextureObject( t ); + if ( in_use && + offset == t->memBlock->ofs && size == t->memBlock->size ) { + /* Matching placeholder already exists */ + return; + } else { + driDestroyTextureObject( t ); + } } } } @@ -338,11 +415,12 @@ t->memBlock = mmAllocMem( heap->memory_heap, size, 0, offset ); if ( t->memBlock == NULL ) { - fprintf( stderr, "Couldn't alloc placeholder sz %x ofs %x\n", + fprintf( stderr, "Couldn't alloc placeholder: heap %u sz %x ofs %x\n", +heap->heapId, (int)size, (int)offset ); mmDumpMemInfo( heap->memory_heap ); return; } + t->heap = heap; insert_at_head( & heap->texture_objects, t ); } } @@ -361,7 +439,7 @@ void driAgeTextures( driTexHeap * heap ) { - driTexRegion * list = heap->global_regions; + drmTextureRegionPtr list = heap->global_regions; unsigned sz = 1U << (heap->logGranularity); unsigned i, nr = 0; @@ -384,10 +462,9 @@ } if (list[i].age > heap->local_age) - driTexturesGone( heap, i * sz, sz, 1); + driTexturesGone( heap, i * sz, sz, list[i].in_use); } - /* Loop or uninitialized heap detected. Reset. */ @@ -396,6 +473,11 @@ resetGlobalLRU( heap ); } + if ( 0 ) { + printGlobalLRU( heap ); + printLocalLRU( heap ); + } + heap->local_age = heap->global_age[0]; } @@ -473,7 +555,12 @@ break; } - driSwapOutTextureObject( temp ); + /* If this is a placeholder, there's no need to keep it */ + if (temp->tObj) + driSwapOutTextureObject( temp ); + else + driDestroyTextureObject( temp ); + t->memBlock = mmAllocMem( heap->memory_heap, t->totalSize, heap->alignmentShift, 0 ); } @@ -534,7 +621,7 @@ * would be 12. * \param nr_regions Number of regions into which this texture space * should be partitioned - * \param global_regions Array of \c driTexRegion structures in the SAREA + * \param global_regions Array of \c drmTextureRegion structures in the SAREA * \param global_age Pointer to the global texture age in the SAREA * \param swapped_objects Pointer to the list of texture objects that are * not in texture memory (i.e., have been swapped @@ -550,7 +637,7 @@ driTexHeap * driCreateTextureHeap( unsigned heap_id, void * context, unsigned size, unsigned alignmentShift, unsigned nr_regions, - driTexRegion * global_regions, unsigned * global_age, + drmTextureRegionPtr global_regions, unsigned * global_age, driTextureObject * swapped_objects, unsigned texture_object_size, destroy_texture_object_t * destroy_tex_obj @@ -591,7 +678,12 @@ heap->texture_object_size = texture_object_size; heap->destroy_texture_object = destroy_tex_obj; - heap->local_age = 0; + /* Force global heap init */ + if (heap->global_age == 0) + heap->local_age = ~0; + else + heap->local_age = 0; + make_empty_list( & heap->texture_objects ); driSetTextureSwapCounterLocation( heap, NULL ); } @@ -627,6 +719,10 @@ if ( heap != NULL ) { foreach_s( t, temp, & heap->texture_objects ) + { + driDestroyTextureObject( t ); + } + foreach_s( t, temp, heap->swapped_objects ) { driDestroyTextureObject( t ); } Index: lib/GL/mesa/src/drv/common/texmem.h =================================================================== RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/common/Attic/texmem.h,v retrieving revision 1.1.2.6 diff -u -r1.1.2.6 texmem.h --- lib/GL/mesa/src/drv/common/texmem.h 26 Jan 2003 07:43:46 -0000 1.1.2.6 +++ lib/GL/mesa/src/drv/common/texmem.h 1 Feb 2003 21:39:55 -0000 @@ -41,6 +41,7 @@ #include "mtypes.h" #include "mm.h" +#include "xf86drm.h" struct dri_tex_heap; typedef struct dri_tex_heap driTexHeap; @@ -48,8 +49,6 @@ struct dri_texture_object; typedef struct dri_texture_object driTextureObject; -struct dri_texture_region; -typedef struct dri_texture_region driTexRegion; /** * Base texture object type. Each driver will extend this type with its own @@ -78,23 +77,6 @@ }; -/** - * Inter-context texture memory management structure. - * - * Each driver will have an array of driTexRegion structures in its SAREA. - * Each element in the array corresponds to a specific block of texture - * memory. - */ -struct dri_texture_region { - unsigned char next; /**< indices to form a circular LRU */ - unsigned char prev; /**< indices to form a circular LRU */ - unsigned char in_use; /**< owned by a client, or free? */ - unsigned age; /**< tracked by clients to update local LRU's */ -}; - - - - typedef void (destroy_texture_object_t)( void * driverContext, driTextureObject * t ); @@ -148,8 +130,8 @@ /** Pointer to SAREA \a driTexRegion array */ - driTexRegion * global_regions; - + drmTextureRegionPtr global_regions; + /** Pointer to the texture state age (generation number) in the SAREA */ unsigned * global_age; @@ -218,7 +200,7 @@ #define DRI_AGE_TEXTURES( heap ) \ do { \ if ( ((heap) != NULL) \ - && ((heap)->local_age > (heap)->global_age[0]) ) \ + && ((heap)->local_age != (heap)->global_age[0]) ) \ driAgeTextures( heap ); \ } while( 0 ) @@ -243,7 +225,7 @@ driTexHeap * driCreateTextureHeap( unsigned heap_id, void * context, unsigned size, unsigned alignmentShift, unsigned nr_regions, - driTexRegion * global_regions, unsigned * global_age, + drmTextureRegionPtr global_regions, unsigned * global_age, driTextureObject * swapped_objects, unsigned texture_object_size, destroy_texture_object_t * destroy_tex_obj ); void driDestroyTextureHeap( driTexHeap * heap ); Index: lib/GL/mesa/src/drv/mga/mga_xmesa.c =================================================================== RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v retrieving revision 1.38.10.7 diff -u -r1.38.10.7 mga_xmesa.c --- lib/GL/mesa/src/drv/mga/mga_xmesa.c 26 Jan 2003 07:43:46 -0000 1.38.10.7 +++ lib/GL/mesa/src/drv/mga/mga_xmesa.c 1 Feb 2003 21:39:55 -0000 @@ -329,8 +329,8 @@ mgaScreen->textureSize[i], 6, MGA_NR_TEX_REGIONS, - (driTexRegion *) & mmesa->sarea->texList, - (unsigned *) & mmesa->sarea->texAge, + mmesa->sarea->texList[i], + & mmesa->sarea->texAge[i], & mmesa->swapped, sizeof( mgaTextureObject_t ), (destroy_texture_object_t *) mgaDestroyTexObj ); @@ -479,11 +479,9 @@ */ int i; - assert( is_empty_list( & mmesa->swapped ) ); for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) { - assert( is_empty_list( & mmesa->texture_heaps[ i ]->texture_objects ) ); driDestroyTextureHeap( mmesa->texture_heaps[ i ] ); mmesa->texture_heaps[ i ] = NULL; } Index: lib/GL/mesa/src/drv/r128/r128_context.c =================================================================== RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/r128/r128_context.c,v retrieving revision 1.18.36.4 diff -u -r1.18.36.4 r128_context.c --- lib/GL/mesa/src/drv/r128/r128_context.c 5 Dec 2002 15:26:13 -0000 1.18.36.4 +++ lib/GL/mesa/src/drv/r128/r128_context.c 1 Feb 2003 21:39:56 -0000 @@ -138,8 +138,8 @@ r128scrn->texSize[i], 12, R128_NR_TEX_REGIONS, - (driTexRegion *) & rmesa->sarea->texList, - (unsigned *) & rmesa->sarea->texAge, + rmesa->sarea->texList[i], + & rmesa->sarea->texAge[i], & rmesa->swapped, sizeof( r128TexObj ), (destroy_texture_object_t *) r128DestroyTexObj ); @@ -257,11 +257,9 @@ */ int i; - assert( is_empty_list( & rmesa->swapped ) ); for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { - assert( is_empty_list( & rmesa->texture_heaps[ i ]->texture_objects ) ); driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); rmesa->texture_heaps[ i ] = NULL; } Index: lib/GL/mesa/src/drv/r200/r200_context.c =================================================================== RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/r200/r200_context.c,v retrieving revision 1.9.2.4 diff -u -r1.9.2.4 r200_context.c --- lib/GL/mesa/src/drv/r200/r200_context.c 26 Jan 2003 07:43:46 -0000 1.9.2.4 +++ lib/GL/mesa/src/drv/r200/r200_context.c 1 Feb 2003 21:39:58 -0000 @@ -281,8 +281,8 @@ screen->texSize[i], 12, RADEON_NR_TEX_REGIONS, - (driTexRegion *) & rmesa->sarea->texList, - (unsigned *) & rmesa->sarea->texAge, + rmesa->sarea->texList[i], + (unsigned *) & rmesa->sarea->texAge[i], & rmesa->swapped, sizeof( r200TexObj ), (destroy_texture_object_t *) r200DestroyTexObj ); @@ -472,11 +472,9 @@ */ int i; - assert( is_empty_list( & rmesa->swapped ) ); for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { - assert( is_empty_list( & rmesa->texture_heaps[ i ]->texture_objects ) ); driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); rmesa->texture_heaps[ i ] = NULL; } Index: lib/GL/mesa/src/drv/radeon/radeon_context.c =================================================================== RCS file: /cvsroot/dri/xc/xc/lib/GL/mesa/src/drv/radeon/radeon_context.c,v retrieving revision 1.20.2.7 diff -u -r1.20.2.7 radeon_context.c --- lib/GL/mesa/src/drv/radeon/radeon_context.c 5 Dec 2002 15:26:34 -0000 1.20.2.7 +++ lib/GL/mesa/src/drv/radeon/radeon_context.c 1 Feb 2003 21:40:02 -0000 @@ -279,8 +279,8 @@ screen->texSize[i], 12, RADEON_NR_TEX_REGIONS, - (driTexRegion *) & rmesa->sarea->texList, - (unsigned *) & rmesa->sarea->texAge, + rmesa->sarea->texList[i], + & rmesa->sarea->texAge[i], & rmesa->swapped, sizeof( radeonTexObj ), (destroy_texture_object_t *) radeonDestroyTexObj ); @@ -460,11 +460,9 @@ */ int i; - assert( is_empty_list( & rmesa->swapped ) ); for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { - assert( is_empty_list( & rmesa->texture_heaps[ i ]->texture_objects ) ); driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); rmesa->texture_heaps[ i ] = NULL; } Index: programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/r128_drm.h =================================================================== RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/r128_drm.h,v retrieving revision 1.2.12.1 diff -u -r1.2.12.1 r128_drm.h --- programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/r128_drm.h 6 Nov 2002 00:53:07 -0000 1.2.12.1 +++ programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/r128_drm.h 1 Feb 2003 +21:40:07 -0000 @@ -162,7 +162,7 @@ unsigned int last_dispatch; drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; - int tex_age[R128_NR_TEX_HEAPS]; + unsigned int tex_age[R128_NR_TEX_HEAPS]; int ctx_owner; } drm_r128_sarea_t; Index: programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h =================================================================== RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h,v retrieving revision 1.6.2.1 diff -u -r1.6.2.1 radeon_drm.h --- programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h 6 Nov 2002 00:53:07 -0000 1.6.2.1 +++ programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h 1 Feb +2003 21:40:07 -0000 @@ -323,12 +323,6 @@ typedef struct { - unsigned char next, prev; - unsigned char in_use; - int age; -} drm_radeon_tex_region_t; - -typedef struct { /* The channel for communication of state information to the * kernel on firing a vertex buffer with either of the * obsoleted vertex/index ioctls. @@ -350,8 +344,8 @@ unsigned int last_dispatch; unsigned int last_clear; - drm_radeon_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; - int tex_age[RADEON_NR_TEX_HEAPS]; + drm_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; + unsigned int tex_age[RADEON_NR_TEX_HEAPS]; int ctx_owner; int pfState; /* number of 3d windows (0,1,2ormore) */ int pfCurrentPage; /* which buffer is being displayed? */ Index: programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h =================================================================== RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h,v retrieving revision 1.10.48.1 diff -u -r1.10.48.1 r128_sarea.h --- programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h 11 Nov 2002 23:32:30 -0000 1.10.48.1 +++ programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h 1 Feb 2003 21:40:09 +-0000 @@ -149,12 +149,6 @@ } r128_texture_regs_t; typedef struct { - unsigned char next, prev; /* indices to form a circular LRU */ - unsigned char in_use; /* owned by a client, or free? */ - int age; /* tracked by clients to update local LRU's */ -} r128_tex_region_t; - -typedef struct { /* The channel for communication of state information to the kernel * on firing a vertex buffer. */ @@ -191,9 +185,9 @@ * else's - simply eject them all in LRU order. */ /* Last elt is sentinal */ - r128_tex_region_t texList[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + drmTextureRegion texList[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; /* last time texture was uploaded */ - int texAge[R128_NR_TEX_HEAPS]; + unsigned int texAge[R128_NR_TEX_HEAPS]; int ctxOwner; /* last context to upload state */ } R128SAREAPriv, *R128SAREAPrivPtr; Index: programs/Xserver/hw/xfree86/drivers/ati/radeon_sarea.h =================================================================== RCS file: /cvsroot/dri/xc/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_sarea.h,v retrieving revision 1.6.14.1 diff -u -r1.6.14.1 radeon_sarea.h --- programs/Xserver/hw/xfree86/drivers/ati/radeon_sarea.h 11 Nov 2002 23:32:31 -0000 1.6.14.1 +++ programs/Xserver/hw/xfree86/drivers/ati/radeon_sarea.h 1 Feb 2003 21:40:14 +-0000 @@ -185,12 +185,6 @@ } radeon_texture_regs_t; typedef struct { - unsigned char next, prev; /* indices to form a circular LRU */ - unsigned char in_use; /* owned by a client, or free? */ - int age; /* tracked by clients to update local LRU's */ -} radeon_tex_region_t; - -typedef struct { /* The channel for communication of state information to the kernel * on firing a vertex buffer. */ @@ -224,9 +218,9 @@ * else's - simply eject them all in LRU order. */ /* Last elt is sentinal */ - radeon_tex_region_t texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; + drmTextureRegion texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; /* last time texture was uploaded */ - int texAge[RADEON_NR_TEX_HEAPS]; + unsigned int texAge[RADEON_NR_TEX_HEAPS]; int ctxOwner; /* last context to upload state */ int pfAllowPageFlip; /* set by the 2d driver, read by the client */