diff options
Diffstat (limited to 'src/mesa/drivers/dri/gamma/gamma_texmem.c')
-rw-r--r-- | src/mesa/drivers/dri/gamma/gamma_texmem.c | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/gamma/gamma_texmem.c b/src/mesa/drivers/dri/gamma/gamma_texmem.c new file mode 100644 index 0000000000..506b5c4c8f --- /dev/null +++ b/src/mesa/drivers/dri/gamma/gamma_texmem.c @@ -0,0 +1,535 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/gamma/gamma_texmem.c,v 1.5 2002/11/05 17:46:07 tsi Exp $ */ + +#include <stdlib.h> +#include <stdio.h> + +#include "glheader.h" +#include "colormac.h" +#include "macros.h" +#include "mtypes.h" +#include "simple_list.h" +#include "enums.h" + +#include "mm.h" +#include "glint_dri.h" +#include "gamma_context.h" +#include "gamma_lock.h" + +void gammaDestroyTexObj(gammaContextPtr gmesa, gammaTextureObjectPtr t) +{ + if (!t) return; + + /* 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 (gmesa && t->age > gmesa->dirtyAge) + gmesa->dirtyAge = t->age; + } + + if (t->globj) + t->globj->DriverData = 0; + + if (gmesa) { + if (gmesa->CurrentTexObj[0] == t) { + gmesa->CurrentTexObj[0] = 0; + gmesa->dirty &= ~GAMMA_UPLOAD_TEX0; + } + +#if 0 + if (gmesa->CurrentTexObj[1] == t) { + gmesa->CurrentTexObj[1] = 0; + gmesa->dirty &= ~GAMMA_UPLOAD_TEX1; + } +#endif + } + + remove_from_list(t); + free(t); +} + + +void gammaSwapOutTexObj(gammaContextPtr gmesa, gammaTextureObjectPtr t) +{ +/* fprintf(stderr, "%s\n", __FUNCTION__); */ + + if (t->MemBlock) { + mmFreeMem(t->MemBlock); + t->MemBlock = 0; + + if (t->age > gmesa->dirtyAge) + gmesa->dirtyAge = t->age; + } + + t->dirty_images = ~0; + move_to_tail(&(gmesa->SwappedOut), t); +} + + + +/* Upload an image from mesa's internal copy. + */ +static void gammaUploadTexLevel( gammaContextPtr gmesa, gammaTextureObjectPtr t, int level ) +{ + const struct gl_texture_image *image = t->image[level].image; + int i,j; + int l2d; +#if 0 + int offset = 0; +#endif + int words, depthLog2; + + /* fprintf(stderr, "%s\n", __FUNCTION__); */ + + l2d = 5; /* 32bits per texel == 1<<5 */ + + if (level == 0) { + t->TextureAddressMode &= ~(TAM_WidthMask | TAM_HeightMask); + t->TextureAddressMode |= (image->WidthLog2 << 9) | + (image->HeightLog2 << 13); + t->TextureReadMode &= ~(TRM_WidthMask | TRM_HeightMask | + TRM_DepthMask | TRM_Border | + TRM_Patch); + t->TextureReadMode |= (image->WidthLog2 << 1) | + (image->HeightLog2 << 5) | + (l2d << 9); + t->TextureFormat &= ~(TF_CompnentsMask | TF_OneCompFmt_Mask); + } + + t->TextureBaseAddr[level] = /* ??? */ + (unsigned long)(t->image[level].offset + t->BufAddr) << 5; + + CALC_LOG2(depthLog2, 1<<l2d); + words = (image->Width * image->Height) >> (5-depthLog2); + + CHECK_DMA_BUFFER(gmesa, 3); + WRITE(gmesa->buf, LBWindowBase, t->TextureBaseAddr[level] >> 5); + WRITE(gmesa->buf, TextureCacheControl, (TCC_Enable | TCC_Invalidate)); + WRITE(gmesa->buf, WaitForCompletion, 0); + FLUSH_DMA_BUFFER(gmesa); + + switch (t->image[level].internalFormat) { + case GL_RGB: + case 3: + { + GLubyte *src = (GLubyte *)image->Data; + + if (level == 0) + t->TextureFormat |= TF_Compnents_3; + +#if 0 /* This is the texture download code we SHOULD be using */ + /* In the routines below, but this causes an DMA overrun - WHY ? */ + while (offset < words) { + int count = gmesa->bufSize; + int i; + count -= 3; + if (count > words-offset) count = words-offset; + + gmesa->buf->i = GlintTextureDownloadOffsetTag; + gmesa->buf++; + gmesa->buf->i = offset; + gmesa->buf++; + gmesa->buf->i = (GlintTextureDataTag | ((count-1) << 16)); + gmesa->buf++; + + for (i = 0; i < count; i++) { + gmesa->buf->i = PACK_COLOR_565(src[0],src[1],src[2]); + gmesa->buf++; + src += 3; + } + + gmesa->bufCount = count+3; /* texture data + 3 values */ + offset += count; + + FLUSH_DMA_BUFFER(gmesa); + } +#else + /* The UGLY way, and SLOW !, but the above sometimes causes + * a DMA overrun error ??? FIXME ! */ + + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureDownloadOffset, 0); + for (i = 0; i < words; i++) { + unsigned int data; + data = PACK_COLOR_565(src[0],src[1],src[2]); + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureData, data); + src += 3; + } + FLUSH_DMA_BUFFER(gmesa); +#endif + } + break; + + case GL_RGBA: + case 4: + { + GLubyte *src = (GLubyte *)image->Data; + + if (level == 0) + t->TextureFormat |= TF_Compnents_4; + + /* The UGLY way, and SLOW !, but the above sometimes causes + * a DMA overrun error ??? FIXME ! */ + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureDownloadOffset, 0); + for (i = 0; i < words; i++) { + unsigned int data; + data = PACK_COLOR_8888(src[0],src[1],src[2],src[3]); + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureData, data); + src += 4; + } + FLUSH_DMA_BUFFER(gmesa); + } + break; + + case GL_LUMINANCE: + { + GLubyte *src = (GLubyte *)image->Data; + + if (level == 0) + t->TextureFormat |= TF_Compnents_1 | TF_OneCompFmt_Lum; + + /* The UGLY way, and SLOW !, but the above sometimes causes + * a DMA overrun error ??? FIXME ! */ + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureDownloadOffset, 0); + for (i = 0; i < words; i++) { + unsigned int data; + data = PACK_COLOR_888(src[0],src[0],src[0]); + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureData, data); + src ++; + } + FLUSH_DMA_BUFFER(gmesa); + } + break; + + case GL_INTENSITY: + { + GLubyte *src = (GLubyte *)image->Data; + + if (level == 0) + t->TextureFormat |= TF_Compnents_1 | TF_OneCompFmt_Intensity; + + /* The UGLY way, and SLOW !, but the above sometimes causes + * a DMA overrun error ??? FIXME ! */ + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureDownloadOffset, 0); + for (i = 0; i < words; i++) { + unsigned int data; + data = PACK_COLOR_8888(src[0],src[0],src[0],src[0]); + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureData, data); + src ++; + } + FLUSH_DMA_BUFFER(gmesa); + } + break; + + case GL_LUMINANCE_ALPHA: + { + GLubyte *src = (GLubyte *)image->Data; + + if (level == 0) + t->TextureFormat |= TF_Compnents_2; + + /* The UGLY way, and SLOW !, but the above sometimes causes + * a DMA overrun error ??? FIXME ! */ + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureDownloadOffset, 0); + for (i = 0; i < words; i++) { + unsigned int data; + data = PACK_COLOR_8888(src[0],src[0],src[0],src[1]); + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureData, data); + src += 2; + } + FLUSH_DMA_BUFFER(gmesa); + } + break; + + case GL_ALPHA: + { + GLubyte *src = (GLubyte *)image->Data; + + if (level == 0) + t->TextureFormat |= TF_Compnents_1 | TF_OneCompFmt_Alpha; + + /* The UGLY way, and SLOW !, but the above sometimes causes + * a DMA overrun error ??? FIXME ! */ + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureDownloadOffset, 0); + for (i = 0; i < words; i++) { + unsigned int data; + data = PACK_COLOR_8888(255,255,255,src[0]); + CHECK_DMA_BUFFER(gmesa, 1); + WRITE(gmesa->buf, TextureData, data); + src += 1; + } + FLUSH_DMA_BUFFER(gmesa); + } + break; + + /* TODO: Translate color indices *now*: + */ + case GL_COLOR_INDEX: + { + GLubyte *dst = (GLubyte *)(t->BufAddr + t->image[level].offset); + GLubyte *src = (GLubyte *)image->Data; + + 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)); + } + + CHECK_DMA_BUFFER(gmesa, 2); + WRITE(gmesa->buf, WaitForCompletion, 0); + WRITE(gmesa->buf, LBWindowBase, gmesa->LBWindowBase); +} + +void gammaPrintLocalLRU( gammaContextPtr gmesa ) +{ + gammaTextureObjectPtr t; + int sz = 1 << (gmesa->gammaScreen->logTextureGranularity); + + foreach( t, &gmesa->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 gammaPrintGlobalLRU( gammaContextPtr gmesa ) +{ + int i, j; + GAMMATextureRegionPtr list = gmesa->sarea->texList; + + for (i = 0, j = GAMMA_NR_TEX_REGIONS ; i < GAMMA_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 == GAMMA_NR_TEX_REGIONS) break; + } + + if (j != GAMMA_NR_TEX_REGIONS) + fprintf(stderr, "Loop detected in global LRU\n"); +} + + +void gammaResetGlobalLRU( gammaContextPtr gmesa ) +{ + GAMMATextureRegionPtr list = gmesa->sarea->texList; + int sz = 1 << gmesa->gammaScreen->logTextureGranularity; + int i; + + /* (Re)initialize the global circular LRU list. The last element + * in the array (GAMMA_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 <= gmesa->gammaScreen->textureSize ; i++) { + list[i].prev = i-1; + list[i].next = i+1; + list[i].age = 0; + } + + i--; + list[0].prev = GAMMA_NR_TEX_REGIONS; + list[i].prev = i-1; + list[i].next = GAMMA_NR_TEX_REGIONS; + list[GAMMA_NR_TEX_REGIONS].prev = i; + list[GAMMA_NR_TEX_REGIONS].next = 0; + gmesa->sarea->texAge = 0; +} + + +void gammaUpdateTexLRU( gammaContextPtr gmesa, gammaTextureObjectPtr t ) +{ + int i; + int logsz = gmesa->gammaScreen->logTextureGranularity; + int start = t->MemBlock->ofs >> logsz; + int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz; + GAMMATextureRegionPtr list = gmesa->sarea->texList; + + gmesa->texAge = ++gmesa->sarea->texAge; + + /* Update our local LRU + */ + move_to_head( &(gmesa->TexObjList), t ); + + /* Update the global LRU + */ + for (i = start ; i <= end ; i++) { + + list[i].in_use = 1; + list[i].age = gmesa->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 = GAMMA_NR_TEX_REGIONS; + list[i].next = list[GAMMA_NR_TEX_REGIONS].next; + list[(unsigned)list[GAMMA_NR_TEX_REGIONS].next].prev = i; + list[GAMMA_NR_TEX_REGIONS].next = i; + } +} + + +/* 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 gammaTexturesGone( gammaContextPtr gmesa, + GLuint offset, + GLuint size, + GLuint in_use ) +{ + gammaTextureObjectPtr t, tmp; + + foreach_s ( t, tmp, &gmesa->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. + */ + gammaSwapOutTexObj( gmesa, t ); + } + + if (in_use) { + t = (gammaTextureObjectPtr) calloc(1,sizeof(*t)); + if (!t) return; + + t->MemBlock = mmAllocMem( gmesa->texHeap, size, 0, offset); + insert_at_head( &gmesa->TexObjList, t ); + } + + /* Reload any lost textures referenced by current vertex buffer. + */ +#if 0 + if (gmesa->vertex_buffer) { + int i, j; + + fprintf(stderr, "\n\nreload tex\n"); + + for (i = 0 ; i < gmesa->statenr ; i++) { + for (j = 0 ; j < 2 ; j++) { + gammaTextureObjectPtr t = gmesa->state_tex[j][i]; + if (t) { + if (t->MemBlock == 0) + gammaUploadTexImages( gmesa, t ); + } + } + } + + /* Hard to do this with the lock held: + */ +/* GAMMA_FIREVERTICES( gmesa ); */ + } +#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 gammaUploadTexImages( gammaContextPtr gmesa, gammaTextureObjectPtr t ) +{ + int i; + int ofs; + int numLevels; + + /* /fprintf(stderr, "%s\n", __FUNCTION__); */ +#if 0 + LOCK_HARDWARE( gmesa ); +#endif + + /* Do we need to eject LRU texture objects? + */ + if (!t->MemBlock) { + while (1) + { + t->MemBlock = mmAllocMem( gmesa->texHeap, t->totalSize, 12, 0 ); + if (t->MemBlock) + break; + + if (gmesa->TexObjList.prev == gmesa->CurrentTexObj[0] || + gmesa->TexObjList.prev == gmesa->CurrentTexObj[1]) { + fprintf(stderr, "Hit bound texture in upload\n"); + gammaPrintLocalLRU( gmesa ); + return; + } + + if (gmesa->TexObjList.prev == &(gmesa->TexObjList)) { + fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize); + mmDumpMemInfo( gmesa->texHeap ); + return; + } + + gammaSwapOutTexObj( gmesa, gmesa->TexObjList.prev ); + } + + ofs = t->MemBlock->ofs; + t->BufAddr = (char *)(unsigned long)(gmesa->LBWindowBase + ofs); /* ??? */ + + if (t == gmesa->CurrentTexObj[0]) + gmesa->dirty |= GAMMA_UPLOAD_TEX0; + +#if 0 + if (t == gmesa->CurrentTexObj[1]) + gmesa->dirty |= GAMMA_UPLOAD_TEX1; +#endif + + gammaUpdateTexLRU( gmesa, t ); + } + +#if 0 + if (gmesa->dirtyAge >= GET_DISPATCH_AGE(gmesa)) + gammaWaitAgeLocked( gmesa, gmesa->dirtyAge ); +#endif + + numLevels = t->lastLevel - t->firstLevel + 1; + for (i = 0 ; i < numLevels ; i++) + if (t->dirty_images & (1<<i)) + gammaUploadTexLevel( gmesa, t, i ); + + t->dirty_images = 0; + +#if 0 + UNLOCK_HARDWARE( gmesa ); +#endif +} |