diff options
Diffstat (limited to 'src/mesa/drivers/dri/s3v/s3v_texmem.c')
-rw-r--r-- | src/mesa/drivers/dri/s3v/s3v_texmem.c | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/s3v/s3v_texmem.c b/src/mesa/drivers/dri/s3v/s3v_texmem.c new file mode 100644 index 0000000000..ab2e67d182 --- /dev/null +++ b/src/mesa/drivers/dri/s3v/s3v_texmem.c @@ -0,0 +1,583 @@ +/* + * Author: Max Lingua <sunmax@libero.it> + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "simple_list.h" +#include "enums.h" + +#include "mm.h" +#include "mem.h" +#include "s3v_context.h" +#include "s3v_lock.h" +#include "s3v_tex.h" + +void s3vSwapOutTexObj(s3vContextPtr vmesa, s3vTextureObjectPtr t); +void s3vUpdateTexLRU( s3vContextPtr vmesa, s3vTextureObjectPtr t ); + + +void s3vDestroyTexObj(s3vContextPtr vmesa, s3vTextureObjectPtr t) +{ +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vDestroyTexObj: #%i ***\n", ++times)); +#endif + + if (!t) return; + +/* FIXME: useful? */ +#if _TEXFLUSH + if (vmesa) + DMAFLUSH(); +#endif + + /* This is sad - need to sync *in case* we upload a texture + * to this newly free memory... + */ + if (t->MemBlock) { + mmFreeMem(t->MemBlock); + t->MemBlock = 0; + + if (vmesa && t->age > vmesa->dirtyAge) + vmesa->dirtyAge = t->age; + } + + if (t->globj) + t->globj->DriverData = NULL; + + if (vmesa) { + if (vmesa->CurrentTexObj[0] == t) { + vmesa->CurrentTexObj[0] = 0; + vmesa->dirty &= ~S3V_UPLOAD_TEX0; + } + +#if 0 + if (vmesa->CurrentTexObj[1] == t) { + vmesa->CurrentTexObj[1] = 0; + vmesa->dirty &= ~S3V_UPLOAD_TEX1; + } +#endif + } + + remove_from_list(t); + FREE(t); +} + + +void s3vSwapOutTexObj(s3vContextPtr vmesa, s3vTextureObjectPtr t) +{ +/* int i; */ +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vSwapOutTexObj: #%i ***\n", ++times)); +#endif + + if (t->MemBlock) { + + mmFreeMem(t->MemBlock); + t->MemBlock = 0; + + if (t->age > vmesa->dirtyAge) + vmesa->dirtyAge = t->age; + + t->dirty_images = ~0; + move_to_tail(&(vmesa->SwappedOut), t); + } +} + + +/* Upload an image from mesa's internal copy. + */ + +static void s3vUploadTexLevel( s3vContextPtr vmesa, s3vTextureObjectPtr t, + int level ) +{ + __DRIscreenPrivate *sPriv = vmesa->driScreen; + const struct gl_texture_image *image = t->image[level].image; + int i,j; + int l2d; + /* int offset = 0; */ + int words; + CARD32* dest; +#if TEX_DEBUG_ON + static unsigned int times=0; +#endif + if ( !image ) return; + if (image->Data == 0) return; + + DEBUG_TEX(("*** s3vUploadTexLevel: #%i ***\n", ++times)); + DEBUG_TEX(("level = %i\n", level)); + + l2d = 5; /* 32bits per texel == 1<<5 */ +/* + if (level == 0) + ; +*/ + DEBUG_TEX(("t->image[%i].offset = 0x%x\n", + level, t->image[level].offset)); + + t->TextureBaseAddr[level] = (CARD32)(t->BufAddr + t->image[level].offset + + _TEXALIGN) & (CARD32)(~_TEXALIGN); + dest = (CARD32*)(sPriv->pFB + t->TextureBaseAddr[level]); + + DEBUG_TEX(("sPriv->pFB = 0x%x\n", sPriv->pFB)); + DEBUG_TEX(("dest = 0x%x\n", dest)); + DEBUG_TEX(("dest - sPriv->pFB = 0x%x\n", ((int)dest - (int)sPriv->pFB))); + + /* NOTE: we implicitly suppose t->texelBytes == 2 */ + + words = (image->Width * image->Height) >> 1; + + DEBUG_TEX(("\n\n")); + + switch (t->image[level].internalFormat) { + case GL_RGB: + case 3: + { + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_RGB:\n")); +/* + if (level == 0) + ; +*/ + /* The UGLY way, and SLOW : use DMA FIXME ! */ + + for (i = 0; i < words; i++) { + unsigned int data; + /* data = PACK_COLOR_565(src[0],src[1],src[2]); */ + data = S3VIRGEPACKCOLOR555(src[0],src[1],src[2],255) + |(S3VIRGEPACKCOLOR555(src[3],src[4],src[5],255)<<16); + + *dest++ = data; + /* src += 3; */ + src +=6; + } + } + break; + + case GL_RGBA: + case 4: + { + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_RGBA:\n")); +/* + if (level == 0) + ; +*/ + for (i = 0; i < words; i++) { + unsigned int data; + + /* data = PACK_COLOR_8888(src[0],src[1],src[2],src[3]); */ + data = S3VIRGEPACKCOLOR4444(src[0], src[1],src[2], src[3]) + | (S3VIRGEPACKCOLOR4444(src[4], src[5], src[6], src[7]) << 16); + + *dest++ = data; + /* src += 4; */ + src += 8; + } + } + break; + + case GL_LUMINANCE: + { + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_LUMINANCE:\n")); +/* + if (level == 0) + ; +*/ + for (i = 0; i < words; i++) { + unsigned int data; + + /* data = PACK_COLOR_888(src[0],src[0],src[0]); */ + data = S3VIRGEPACKCOLOR4444(src[0],src[0],src[0],src[0]) + | (S3VIRGEPACKCOLOR4444(src[1],src[1],src[1],src[1]) << 16); + + *dest++ = data; + /* src ++; */ + src +=2; + } + } + break; + + case GL_INTENSITY: + { + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_INTENSITY:\n")); +/* + if (level == 0) + ; +*/ + for (i = 0; i < words; i++) { + unsigned int data; + + /* data = PACK_COLOR_8888(src[0],src[0],src[0],src[0]); */ + data = S3VIRGEPACKCOLOR4444(src[0],src[0],src[0],src[0]) + | (S3VIRGEPACKCOLOR4444(src[1],src[1],src[1],src[1]) << 16); + + *dest++ = data; + /* src ++; */ + src += 2; + } + } + break; + + case GL_LUMINANCE_ALPHA: + { + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_LUMINANCE_ALPHA:\n")); +/* + if (level == 0) + ; +*/ + for (i = 0; i < words; i++) { + unsigned int data; + + /* data = PACK_COLOR_8888(src[0],src[0],src[0],src[1]); */ + data = S3VIRGEPACKCOLOR4444(src[0],src[0],src[0],src[1]) + | (S3VIRGEPACKCOLOR4444(src[2],src[2],src[2],src[3]) << 16); + + *dest++ = data; + /* src += 2; */ + src += 4; + } + } + break; + + case GL_ALPHA: + { + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_ALPHA:\n")); +/* + if (level == 0) + ; +*/ + for (i = 0; i < words; i++) { + unsigned int data; + + /* data = PACK_COLOR_8888(255,255,255,src[0]); */ + data = S3VIRGEPACKCOLOR4444(255,255,255,src[0]) + | (S3VIRGEPACKCOLOR4444(255,255,255,src[1]) << 16); + + *dest++ = data; + /* src += 1; */ + src += 2; + } + } + break; + + /* TODO: Translate color indices *now*: + */ + case GL_COLOR_INDEX: + { + + GLubyte *dst = (GLubyte *)(t->BufAddr + t->image[level].offset); + GLubyte *src = (GLubyte *)image->Data; + + DEBUG_TEX(("GL_COLOR_INDEX:\n")); + + for (j = 0 ; j < image->Height ; j++, dst += t->Pitch) { + for (i = 0 ; i < image->Width ; i++) { + dst[i] = src[0]; + src += 1; + } + } + } + break; + + default: + fprintf(stderr, "Not supported texture format %s\n", + _mesa_lookup_enum_by_nr(image->Format)); + } + + DEBUG_TEX(("words = %i\n\n", words)); +} + +void s3vPrintLocalLRU( s3vContextPtr vmesa ) +{ + s3vTextureObjectPtr t; + int sz = 1 << (vmesa->s3vScreen->logTextureGranularity); + +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vPrintLocalLRU: #%i ***\n", ++times)); +#endif + + foreach( t, &vmesa->TexObjList ) { + if (!t->globj) + fprintf(stderr, "Placeholder %d at %x sz %x\n", + t->MemBlock->ofs / sz, + t->MemBlock->ofs, + t->MemBlock->size); + else + fprintf(stderr, "Texture at %x sz %x\n", + t->MemBlock->ofs, + t->MemBlock->size); + + } +} + +void s3vPrintGlobalLRU( s3vContextPtr vmesa ) +{ + int i, j; + S3VTexRegionPtr list = vmesa->sarea->texList; +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vPrintGlobalLRU: #%i ***\n", ++times)); +#endif + + for (i = 0, j = S3V_NR_TEX_REGIONS ; i < S3V_NR_TEX_REGIONS ; i++) { + fprintf(stderr, "list[%d] age %d next %d prev %d\n", + j, list[j].age, list[j].next, list[j].prev); + j = list[j].next; + if (j == S3V_NR_TEX_REGIONS) break; + } + + if (j != S3V_NR_TEX_REGIONS) + fprintf(stderr, "Loop detected in global LRU\n"); +} + + +void s3vResetGlobalLRU( s3vContextPtr vmesa ) +{ + S3VTexRegionPtr list = vmesa->sarea->texList; + int sz = 1 << vmesa->s3vScreen->logTextureGranularity; + int i; + +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vResetGlobalLRU: #%i ***\n", ++times)); +#endif + + /* (Re)initialize the global circular LRU list. The last element + * in the array (S3V_NR_TEX_REGIONS) is the sentinal. Keeping it + * at the end of the array allows it to be addressed rationally + * when looking up objects at a particular location in texture + * memory. + */ + for (i = 0 ; (i+1) * sz <= vmesa->s3vScreen->textureSize ; i++) { + list[i].prev = i-1; + list[i].next = i+1; + list[i].age = 0; + } + + i--; + list[0].prev = S3V_NR_TEX_REGIONS; + list[i].prev = i-1; + list[i].next = S3V_NR_TEX_REGIONS; + list[S3V_NR_TEX_REGIONS].prev = i; + list[S3V_NR_TEX_REGIONS].next = 0; + vmesa->sarea->texAge = 0; +} + + +void s3vUpdateTexLRU( s3vContextPtr vmesa, s3vTextureObjectPtr t ) +{ +/* + int i; + int logsz = vmesa->s3vScreen->logTextureGranularity; + int start = t->MemBlock->ofs >> logsz; + int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz; + S3VTexRegionPtr list = vmesa->sarea->texList; +*/ + +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vUpdateTexLRU: #%i ***\n", ++times)); +#endif + + vmesa->texAge = ++vmesa->sarea->texAge; + + /* Update our local LRU + */ + move_to_head( &(vmesa->TexObjList), t ); + + /* Update the global LRU + */ +#if 0 + for (i = start ; i <= end ; i++) { + + list[i].in_use = 1; + list[i].age = vmesa->texAge; + + /* remove_from_list(i) + */ + list[(unsigned)list[i].next].prev = list[i].prev; + list[(unsigned)list[i].prev].next = list[i].next; + + /* insert_at_head(list, i) + */ + list[i].prev = S3V_NR_TEX_REGIONS; + list[i].next = list[S3V_NR_TEX_REGIONS].next; + list[(unsigned)list[S3V_NR_TEX_REGIONS].next].prev = i; + list[S3V_NR_TEX_REGIONS].next = i; + } +#endif +} + + +/* Called for every shared texture region which has increased in age + * since we last held the lock. + * + * Figures out which of our textures have been ejected by other clients, + * and pushes a placeholder texture onto the LRU list to represent + * the other client's textures. + */ +void s3vTexturesGone( s3vContextPtr vmesa, + GLuint offset, + GLuint size, + GLuint in_use ) +{ + s3vTextureObjectPtr t, tmp; +#if TEX_DEBUG_ON + static unsigned int times=0; + DEBUG_TEX(("*** s3vTexturesGone: #%i ***\n", ++times)); +#endif + + foreach_s ( t, tmp, &vmesa->TexObjList ) { + + if (t->MemBlock->ofs >= offset + size || + t->MemBlock->ofs + t->MemBlock->size <= offset) + continue; + + /* It overlaps - kick it off. Need to hold onto the currently bound + * objects, however. + */ + s3vSwapOutTexObj( vmesa, t ); + } + + if (in_use) { + t = (s3vTextureObjectPtr) calloc(1,sizeof(*t)); + if (!t) return; + + t->MemBlock = mmAllocMem( vmesa->texHeap, size, 0, offset); + insert_at_head( &vmesa->TexObjList, t ); + } + + /* Reload any lost textures referenced by current vertex buffer. + */ +#if 0 + if (vmesa->vertex_buffer) { + int i, j; + + fprintf(stderr, "\n\nreload tex\n"); + + for (i = 0 ; i < vmesa->statenr ; i++) { + for (j = 0 ; j < 2 ; j++) { + s3vTextureObjectPtr t = vmesa->state_tex[j][i]; + if (t) { + if (t->MemBlock == 0) + s3vUploadTexImages( vmesa, t ); + } + } + } + + /* Hard to do this with the lock held: + */ + /* S3V_FIREVERTICES( vmesa ); */ + } +#endif +} + + +/* This is called with the lock held. May have to eject our own and/or + * other client's texture objects to make room for the upload. + */ +void s3vUploadTexImages( s3vContextPtr vmesa, s3vTextureObjectPtr t ) +{ + int i; + int ofs; + int numLevels; +#if TEX_DEBUG_ON + static unsigned int times=0; + static unsigned int try=0; + + DEBUG_TEX(("*** s3vUploadTexImages: #%i ***\n", ++times)); + DEBUG_TEX(("vmesa->texHeap = 0x%x; t->totalSize = %i\n", + (unsigned int)vmesa->texHeap, t->totalSize)); +#endif + + /* Do we need to eject LRU texture objects? + */ + if (!t->MemBlock) { + + while (1) + { + /* int try = 0; */ + DEBUG_TEX(("trying to alloc mem for tex (try %i)\n", ++try)); + + t->MemBlock = mmAllocMem( vmesa->texHeap, t->totalSize, 12, 0 ); + + if (t->MemBlock) + break; + + if (vmesa->TexObjList.prev == vmesa->CurrentTexObj[0]) { +/* || vmesa->TexObjList.prev == vmesa->CurrentTexObj[1]) { + fprintf(stderr, "Hit bound texture in upload\n"); + s3vPrintLocalLRU( vmesa ); */ + return; + } + + if (vmesa->TexObjList.prev == &(vmesa->TexObjList)) { +/* fprintf(stderr, "Failed to upload texture, sz %d\n", + t->totalSize); + mmDumpMemInfo( vmesa->texHeap ); */ + return; + } + + DEBUG_TEX(("swapping out: %p\n", vmesa->TexObjList.prev)); + s3vSwapOutTexObj( vmesa, vmesa->TexObjList.prev ); + } + + ofs = t->MemBlock->ofs; + + t->BufAddr = vmesa->s3vScreen->texOffset + ofs; + + DEBUG_TEX(("ofs = 0x%x\n", ofs)); + DEBUG_TEX(("t->BufAddr = 0x%x\n", t->BufAddr)); + +/* FIXME: check if we need it */ +#if 0 + if (t == vmesa->CurrentTexObj[0]) { + vmesa->dirty |= S3V_UPLOAD_TEX0; + vmesa->restore_primitive = -1; + } +#endif + +#if 0 + if (t == vmesa->CurrentTexObj[1]) + vmesa->dirty |= S3V_UPLOAD_TEX1; +#endif + + s3vUpdateTexLRU( vmesa, t ); + } + +#if 0 + if (vmesa->dirtyAge >= GET_DISPATCH_AGE(vmesa)) + s3vWaitAgeLocked( vmesa, vmesa->dirtyAge ); +#endif + +#if _TEXLOCK + S3V_SIMPLE_FLUSH_LOCK(vmesa); +#endif + numLevels = t->lastLevel - t->firstLevel + 1; + for (i = 0 ; i < numLevels ; i++) + if (t->dirty_images & (1<<i)) + s3vUploadTexLevel( vmesa, t, i ); + + t->dirty_images = 0; +#if _TEXLOCK + S3V_SIMPLE_UNLOCK(vmesa); +#endif +} |