#include #include #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<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<dirty_images = 0; #if 0 UNLOCK_HARDWARE( gmesa ); #endif }