summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/gamma/gamma_texmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/gamma/gamma_texmem.c')
-rw-r--r--src/mesa/drivers/dri/gamma/gamma_texmem.c535
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
+}