/* * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include "mm.h" #include "savagecontext.h" #include "savagetex.h" #include "savagetris.h" #include "savageioctl.h" #include "simple_list.h" #include "enums.h" #include "savage_bci.h" #include "macros.h" #include "texformat.h" #include "texstore.h" #include "texobj.h" #include "swrast/swrast.h" /* declarations of static and inline functions */ __inline GLuint GetTiledCoordinates8(GLuint iBufferWidth, GLint x, GLint y); static GLuint GetTiledCoordinates16_4( GLint iBufferWidth,GLint x,GLint y ); static GLuint GetTiledCoordinates16_8( GLint iBufferWidth,GLint x,GLint y ); static GLuint GetTiledCoordinates32_4( GLint iBufferWidth, GLint x, GLint y ); static GLuint GetTiledCoordinates32_8( GLint iBufferWidth, GLint x, GLint y ); __inline GLuint GetTiledCoordinates( GLint iDepth,GLint iBufferWidth,GLint x,GLint y ); __inline void savageUploadImage(savageTextureObjectPtr t, GLuint level, GLuint startx, GLuint starty, GLuint reloc); __inline void savageTileTex(savageTextureObjectPtr tex, GLuint level); /* tile sizes depending on texel color depth */ GLuint gTileWidth[5] = { 64, /* 4-bit */ 64, /* 8-bit */ 64, /* 16-bit */ 0, /* 24-bit */ 32 /* 32-bit */ }; GLuint gTileHeight[5] = { 64, /* 4-bit */ 32, /* 8-bit */ 16, /* 16-bit */ 0, /* 24-bit */ 16 /* 32-bit */ }; __inline GLuint GetTiledCoordinates8(GLuint iBufferWidth, GLint x, GLint y) { GLint x10, x106, x52; GLint y20, y105, y43; GLuint uWidthInTiles; uWidthInTiles = (iBufferWidth + 63) >> 6; x10 = x & 0x3; x52 = (x & 0x3c) >> 2; x106 = (x & 0x7c0) >> 6; y20 = y & 0x7; y43 = (y & 0x18) >> 3; y105 = (y & 0x7e0) >> 5; return ( x10 | (y20 << 2) | (x52 << 5) | (y43 << 9) | ((y105 * uWidthInTiles) + x106) << 11 ); } /* 4-pixel wide subtiles */ static GLuint GetTiledCoordinates16_4( GLint iBufferWidth, GLint x, GLint y ) { GLint x106; GLint x10; GLint x52; GLint y104; GLint y20; GLint y3; GLuint uiWidthInTiles; /* // calculating tiled address */ uiWidthInTiles = (iBufferWidth + 63) >> 6; x10 = x & 0x3; x52 = (x & 0x3c ) >> 2; x106 = (x & 0x7c0) >> 6; y20 = y & 0x7; y3 = (y & 8 ) >> 3; y104 = (y & 0x7f0) >> 4; return( (x10 << 1) | (y20 << 3) | (x52 << 6) | (y3 << 10) | ((y104 * uiWidthInTiles) + x106) << 11 ); } /* 8-pixel wide subtiles */ static GLuint GetTiledCoordinates16_8( GLint iBufferWidth, GLint x, GLint y ) { GLint x106; GLint x20; GLint x53; GLint y104; GLint y20; GLint y3; GLuint uiWidthInTiles; /* // calculating tiled address */ uiWidthInTiles = (iBufferWidth + 63) >> 6; x20 = x & 0x7; x53 = (x & 0x38 ) >> 3; x106 = (x & 0x7c0) >> 6; y20 = y & 0x7; y3 = (y & 8 ) >> 3; y104 = (y & 0x7f0) >> 4; return( (x20 << 1) | (y20 << 4) | (x53 << 7) | (y3 << 10) | ((y104 * uiWidthInTiles) + x106) << 11 ); } /* function pointer set to the correct version in savageDDInitTextureFuncs */ GLuint (*GetTiledCoordinates16) (GLint, GLint, GLint); /* 4-pixel wide subtiles */ static GLuint GetTiledCoordinates32_4( GLint iBufferWidth, GLint x, GLint y ) { GLint x10; GLint y20; GLuint uiWidthInTiles; GLint x42; GLint x105; GLint y3; GLint y104; /* // calculating tiled address */ uiWidthInTiles = (iBufferWidth + 31) >> 5; x10 = x & 0x3; x42 = (x & 0x1c ) >> 2; x105 = (x & 0x7e0) >> 5; y20 = y & 0x7; y3 = (y & 8 ) >> 3; y104 = (y & 0x7f0) >> 4; return( (x10 << 2) | (y20 << 4) | (x42 << 7) | (y3 << 10) | ((y104 * uiWidthInTiles) + x105) << 11 ); } /* 8-pixel wide subtiles */ static GLuint GetTiledCoordinates32_8( GLint iBufferWidth, GLint x, GLint y ) { GLint x20; GLint y20; GLuint uiWidthInTiles; GLint x43; GLint x105; GLint y3; GLint y104; /* // calculating tiled address */ uiWidthInTiles = (iBufferWidth + 31) >> 5; x20 = x & 0x7; x43 = (x & 0x18 ) >> 3; x105 = (x & 0x7e0) >> 5; y20 = y & 0x7; y3 = (y & 8 ) >> 3; y104 = (y & 0x7f0) >> 4; return( (x20 << 2) | (y20 << 5) | (x43 << 8) | (y3 << 10) | ((y104 * uiWidthInTiles) + x105) << 11 ); } /* function pointer set to the correct version in savageDDInitTextureFuncs */ GLuint (*GetTiledCoordinates32) (GLint, GLint, GLint); __inline GLuint GetTiledCoordinates( GLint iDepth, GLint iBufferWidth, GLint x, GLint y ) { /* // don't check for 4 since we only have 3 types of fb */ if (iDepth == 16) { return( GetTiledCoordinates16( iBufferWidth, x, y ) ); } else if (iDepth == 32) { return( GetTiledCoordinates32( iBufferWidth, x, y ) ); } else { return( GetTiledCoordinates8( iBufferWidth, x, y ) ); } } __inline void savageUploadImage(savageTextureObjectPtr t, GLuint level, GLuint startx, GLuint starty, GLuint reloc) { GLuint uMaxTileWidth = gTileWidth[t->texelBytes]; GLuint x, y, w, row, col; const struct gl_texture_image *image = t->image[level].image; GLubyte * dst, * src, * pBuffer; GLint xAdd, yAdd; GLuint uRowSeparator, uChunk = MIN_TILE_CHUNK, uWrap; pBuffer = (GLubyte *)(t->BufAddr + t->image[level].offset); src = (GLubyte *)image->Data; x = startx; y = starty; w = image->Width; if(image->Format == GL_COLOR_INDEX) { if(w < MIN_TILE_CHUNK) { w = MIN_TILE_CHUNK; } else { if((w > 64 ) && (image->Height <= 16)) { reloc = GL_TRUE; if(image->Height == 16) { uChunk = MIN_TILE_CHUNK << 1; } } } if(!reloc & (w > (64 / 2))) { for(row = 0; row < image->Height; row++) { for(col = 0; col < image->Width; col++) { dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + col, y + row); memcpy (dst, src, t->texelBytes); src += t->texelBytes; } } } else { if(reloc & (w > 64)) { uWrap = ((w + 63) >> 6) - 1; for(row = 0; row < image->Height; row++) { for(col = 0; col < image->Width; col++) { xAdd = (col / (4 * 64)) * 64 + col % 64; yAdd = row + ((col / 64) & 3) * uChunk; dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, 64, x + xAdd, y + yAdd); memcpy (dst, src, t->texelBytes); src += t->texelBytes; } } } else { uRowSeparator = 64 * MIN_TILE_CHUNK / w; for(row = 0; row < image->Height; row++) { xAdd = (w * (row / MIN_TILE_CHUNK)) % 64; yAdd = row % MIN_TILE_CHUNK + MIN_TILE_CHUNK * (row / uRowSeparator); for(col = 0; col < image->Width; col++) { dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + xAdd, y + yAdd); memcpy (dst, src, t->texelBytes); src += t->texelBytes; } } } } } else { if(w < MIN_TILE_CHUNK) { w = MIN_TILE_CHUNK; } else { if((w > uMaxTileWidth ) && (image->Height <= 8)) { reloc = GL_TRUE; } } if(!reloc & (w > uMaxTileWidth / 2)) { for(row = 0; row < image->Height; row++) { for(col = 0; col < image->Width; col++) { dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + col, y + row); memcpy (dst, src, t->texelBytes); src += t->texelBytes; } } } else { if(reloc & (w > uMaxTileWidth)) { for(row = 0; row < image->Height; row++) { for(col = 0; col < image->Width; col++) { xAdd = (col / (2 * uMaxTileWidth)) * uMaxTileWidth + col % uMaxTileWidth; yAdd = row + ((col / uMaxTileWidth) & 1) * MIN_TILE_CHUNK; dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + xAdd, y + yAdd); memcpy (dst, src, t->texelBytes); src += t->texelBytes; } } } else { uRowSeparator = uMaxTileWidth * MIN_TILE_CHUNK / w; for(row = 0; row < image->Height; row++) { yAdd = row % MIN_TILE_CHUNK + MIN_TILE_CHUNK * (row / uRowSeparator); xAdd = (w * (row / MIN_TILE_CHUNK)) % uMaxTileWidth; for(col = 0; col < image->Width; col++) { dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + col + xAdd, y + yAdd); memcpy (dst, src, t->texelBytes); src += t->texelBytes; } } } } } } __inline void savageTileTex(savageTextureObjectPtr tex, GLuint level) { GLuint uWidth, uHeight; GLint xOffset, yOffset; GLint xStart=0, yStart=0; GLint minSize; GLuint xRepeat, yRepeat; GLuint startCol, startRow; GLuint reloc; const struct gl_texture_image *image = tex->image[level].image; reloc = GL_FALSE; uWidth = image->Width2; uHeight = image->Height2; if((uWidth > 4) || (uHeight > 4)) minSize = MIN_TILE_CHUNK; else minSize = MIPMAP_CHUNK; if(image->Width >= minSize) xRepeat = 1; else xRepeat = minSize / image->Width; if(image->Height >= minSize) yRepeat = 1; else { yRepeat = minSize / image->Height; if(minSize == MIN_TILE_CHUNK) reloc = GL_TRUE; } if(((uWidth < 4) && (uHeight < 4)) && (tex->texelBytes >= 2)) { if((uWidth == 2) || (uHeight == 2)) { xStart = 4; yStart = 0; } else { xStart = 4; yStart = 4; } } for(xOffset = 0; xOffset < xRepeat; xOffset++) { for(yOffset = 0; yOffset < yRepeat; yOffset++) { startCol = image->Width * xOffset + xStart; startRow = image->Height * yOffset + yStart; savageUploadImage(tex,level, startCol, startRow, reloc); } } } static void savageSetTexWrapping(savageTextureObjectPtr tex, GLenum s, GLenum t) { tex->texParams.sWrapMode = s; tex->texParams.tWrapMode = t; } static void savageSetTexFilter(savageTextureObjectPtr t, GLenum minf, GLenum magf) { t->texParams.minFilter = minf; t->texParams.magFilter = magf; } /* Need a fallback ? */ static void savageSetTexBorderColor(savageTextureObjectPtr t, GLubyte color[4]) { /* t->Setup[SAVAGE_TEXREG_TEXBORDERCOL] = */ t->texParams.boarderColor = SAVAGEPACKCOLOR8888(color[0],color[1],color[2],color[3]); } static savageTextureObjectPtr savageAllocTexObj( struct gl_texture_object *texObj ) { savageTextureObjectPtr t; t = (savageTextureObjectPtr) calloc(1,sizeof(*t)); texObj->DriverData = t; if ( t != NULL ) { /* Initialize non-image-dependent parts of the state: */ t->globj = texObj; /* FIXME Something here to set initial values for other parts of * FIXME t->setup? */ make_empty_list( t ); savageSetTexWrapping(t,texObj->WrapS,texObj->WrapT); savageSetTexFilter(t,texObj->MinFilter,texObj->MagFilter); savageSetTexBorderColor(t,texObj->_BorderChan); } return t; } /* Called by the _mesa_store_teximage[123]d() functions. */ static const struct gl_texture_format * savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat, GLenum format, GLenum type ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); const GLboolean do32bpt = GL_FALSE; const GLboolean force16bpt = GL_FALSE; const GLboolean isSavage4 = (imesa->savageScreen->chipset >= S3_SAVAGE4); (void) format; (void) type; switch ( internalFormat ) { case 4: case GL_RGBA: case GL_COMPRESSED_RGBA: switch ( type ) { case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555; case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: return &_mesa_texformat_argb4444; case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: return &_mesa_texformat_argb1555; default: return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; } case 3: case GL_RGB: case GL_COMPRESSED_RGB: switch ( type ) { case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: return &_mesa_texformat_argb4444; case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: return &_mesa_texformat_argb1555; case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: return &_mesa_texformat_rgb565; default: return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; } case GL_RGBA8: case GL_RGBA12: case GL_RGBA16: return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; case GL_RGB10_A2: return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555; case GL_RGBA4: case GL_RGBA2: return &_mesa_texformat_argb4444; case GL_RGB5_A1: return &_mesa_texformat_argb1555; case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; case GL_RGB5: case GL_RGB4: case GL_R3_G3_B2: return &_mesa_texformat_rgb565; case GL_ALPHA: case GL_COMPRESSED_ALPHA: return isSavage4 ? &_mesa_texformat_a8 : ( do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444); case GL_ALPHA4: return isSavage4 ? &_mesa_texformat_a8 : &_mesa_texformat_argb4444; case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: return isSavage4 ? &_mesa_texformat_a8 : ( !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444); case 1: case GL_LUMINANCE: case GL_COMPRESSED_LUMINANCE: /* no alpha, but use argb1555 in 16bit case to get pure grey values */ return isSavage4 ? &_mesa_texformat_l8 : ( do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555); case GL_LUMINANCE4: return isSavage4 ? &_mesa_texformat_l8 : &_mesa_texformat_argb1555; case GL_LUMINANCE8: case GL_LUMINANCE12: case GL_LUMINANCE16: return isSavage4 ? &_mesa_texformat_l8 : ( !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555); case 2: case GL_LUMINANCE_ALPHA: case GL_COMPRESSED_LUMINANCE_ALPHA: /* Savage4 has a al44 texture format. But it's not supported by Mesa. */ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; case GL_LUMINANCE4_ALPHA4: case GL_LUMINANCE6_ALPHA2: return &_mesa_texformat_argb4444; case GL_LUMINANCE8_ALPHA8: case GL_LUMINANCE12_ALPHA4: case GL_LUMINANCE12_ALPHA12: case GL_LUMINANCE16_ALPHA16: return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; case GL_INTENSITY: case GL_COMPRESSED_INTENSITY: return isSavage4 ? &_mesa_texformat_i8 : ( do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444); case GL_INTENSITY4: return isSavage4 ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444; case GL_INTENSITY8: case GL_INTENSITY12: case GL_INTENSITY16: return isSavage4 ? &_mesa_texformat_i8 : ( !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444); /* case GL_COLOR_INDEX: case GL_COLOR_INDEX1_EXT: case GL_COLOR_INDEX2_EXT: case GL_COLOR_INDEX4_EXT: case GL_COLOR_INDEX8_EXT: case GL_COLOR_INDEX12_EXT: case GL_COLOR_INDEX16_EXT: return &_mesa_texformat_ci8; */ default: _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__); return NULL; } } static void savageSetTexImages( savageContextPtr imesa, const struct gl_texture_object *tObj ) { savageTextureObjectPtr t = (savageTextureObjectPtr) tObj->DriverData; struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel]; GLuint offset, width, pitch, i, textureFormat, log_pitch; assert(t); assert(image); switch (image->TexFormat->MesaFormat) { case MESA_FORMAT_ARGB8888: textureFormat = TFT_ARGB8888; t->texelBytes = 4; break; case MESA_FORMAT_ARGB1555: textureFormat = TFT_ARGB1555; t->texelBytes = 2; break; case MESA_FORMAT_ARGB4444: textureFormat = TFT_ARGB4444; t->texelBytes = 2; break; case MESA_FORMAT_RGB565: textureFormat = TFT_RGB565; t->texelBytes = 2; break; case MESA_FORMAT_L8: textureFormat = TFT_L8; t->texelBytes = 1; break; case MESA_FORMAT_I8: textureFormat = TFT_I8; t->texelBytes = 1; break; case MESA_FORMAT_A8: textureFormat = TFT_A8; t->texelBytes = 1; break; default: _mesa_problem(imesa->glCtx, "Bad texture format in %s", __FUNCTION__); } /* Figure out the size now (and count the levels). Upload won't be done * until later. */ width = image->Width * t->texelBytes; for (pitch = 2, log_pitch=1 ; pitch < width ; pitch *= 2 ) log_pitch++; t->dirty_images = 0; offset = 0; for ( i = 0 ; i < SAVAGE_TEX_MAXLEVELS && tObj->Image[0][i] ; i++ ) { t->image[i].image = tObj->Image[0][i]; t->image[i].offset = offset; t->image[i].internalFormat = textureFormat; t->dirty_images |= (1<image[i].image->Height * pitch; pitch = pitch >> 1; } t->totalSize = offset; t->max_level = i-1; t->min_level = 0; } void savageDestroyTexObj(savageContextPtr imesa, savageTextureObjectPtr 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 (t->age > imesa->dirtyAge) imesa->dirtyAge = t->age; } if (t->globj) t->globj->DriverData = 0; remove_from_list(t); free(t); } static void savageSwapOutTexObj(savageContextPtr imesa, savageTextureObjectPtr t) { if (t->MemBlock) { mmFreeMem(t->MemBlock); t->MemBlock = 0; if (t->age > imesa->dirtyAge) imesa->dirtyAge = t->age; } t->dirty_images = ~0; move_to_tail(&(imesa->SwappedOut), t); } /* Upload an image from mesa's internal copy. */ static void savageUploadTexLevel( savageTextureObjectPtr t, int level ) { const struct gl_texture_image *image = t->image[level].image; /* Need triangle (rather than pixel) fallbacks to simulate this using * normal textured triangles. * * DO THIS IN DRIVER STATE MANAGMENT, not hardware state. * */ if(image->Border != 0) fprintf (stderr, "Not supported texture border %d.\n", (int) image->Border); savageTileTex(t, level); } void savagePrintLocalLRU( savageContextPtr imesa , GLuint heap) { savageTextureObjectPtr t; int sz = 1 << (imesa->savageScreen->logTextureGranularity[heap]); foreach( t, &imesa->TexObjList[heap] ) { 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 (bound %d) at %x sz %x\n", t->bound, t->MemBlock->ofs, t->MemBlock->size); } } void savagePrintGlobalLRU( savageContextPtr imesa , GLuint heap) { int i, j; drm_savage_tex_region_t *list = imesa->sarea->texList[heap]; for (i = 0, j = SAVAGE_NR_TEX_REGIONS ; i < SAVAGE_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 == SAVAGE_NR_TEX_REGIONS) break; } if (j != SAVAGE_NR_TEX_REGIONS) fprintf(stderr, "Loop detected in global LRU\n"); for (i = 0 ; i < SAVAGE_NR_TEX_REGIONS ; i++) { fprintf(stderr,"list[%d] age %d next %d prev %d\n", i, list[i].age, list[i].next, list[i].prev); } } void savageResetGlobalLRU( savageContextPtr imesa, GLuint heap ) { drm_savage_tex_region_t *list = imesa->sarea->texList[heap]; int sz = 1 << imesa->savageScreen->logTextureGranularity[heap]; int i; /* (Re)initialize the global circular LRU list. The last element * in the array (SAVAGE_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 <= imesa->savageScreen->textureSize[heap]; i++) { list[i].prev = i-1; list[i].next = i+1; list[i].age = 0; } i--; list[0].prev = SAVAGE_NR_TEX_REGIONS; list[i].prev = i-1; list[i].next = SAVAGE_NR_TEX_REGIONS; list[SAVAGE_NR_TEX_REGIONS].prev = i; list[SAVAGE_NR_TEX_REGIONS].next = 0; imesa->sarea->texAge[heap] = 0; } static void savageUpdateTexLRU( savageContextPtr imesa, savageTextureObjectPtr t ) { int i; int heap = t->heap; int logsz = imesa->savageScreen->logTextureGranularity[heap]; int start = t->MemBlock->ofs >> logsz; int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz; drm_savage_tex_region_t *list = imesa->sarea->texList[heap]; imesa->texAge[heap] = ++imesa->sarea->texAge[heap]; /* Update our local LRU */ move_to_head( &(imesa->TexObjList[heap]), t ); /* Update the global LRU */ for (i = start ; i <= end ; i++) { list[i].in_use = 1; list[i].age = imesa->texAge[heap]; /* 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 = SAVAGE_NR_TEX_REGIONS; list[i].next = list[SAVAGE_NR_TEX_REGIONS].next; list[(unsigned)list[SAVAGE_NR_TEX_REGIONS].next].prev = i; list[SAVAGE_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 savageTexturesGone( savageContextPtr imesa, GLuint heap, GLuint offset, GLuint size, GLuint in_use ) { savageTextureObjectPtr t, tmp; foreach_s ( t, tmp, &imesa->TexObjList[heap] ) { 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. */ if (t->bound) savageSwapOutTexObj( imesa, t ); else savageDestroyTexObj( imesa, t ); } if (in_use) { t = (savageTextureObjectPtr) calloc(1,sizeof(*t)); if (!t) return; t->heap = heap; t->MemBlock = mmAllocMem( imesa->texHeap[heap], size, 0, offset); if(!t->MemBlock) { free(t); return; } insert_at_head( &imesa->TexObjList[heap], t ); } } /* 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. */ int savageUploadTexImages( savageContextPtr imesa, savageTextureObjectPtr t ) { int heap; int i; int ofs; heap = t->heap = SAVAGE_CARD_HEAP; /* Do we need to eject LRU texture objects? */ if (!t->MemBlock) { while (1) { t->MemBlock = mmAllocMem( imesa->texHeap[heap], t->totalSize, 12, 0 ); if (t->MemBlock) break; else { heap = t->heap = SAVAGE_AGP_HEAP; t->MemBlock = mmAllocMem( imesa->texHeap[heap], t->totalSize, 12, 0 ); if (t->MemBlock) break; } if (imesa->TexObjList[heap].prev->bound) { fprintf(stderr, "Hit bound texture in upload\n"); savagePrintLocalLRU( imesa,heap ); return -1; } if (imesa->TexObjList[heap].prev == &(imesa->TexObjList[heap])) { fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize); mmDumpMemInfo( imesa->texHeap[heap] ); return -1; } savageDestroyTexObj( imesa, imesa->TexObjList[heap].prev ); } ofs = t->MemBlock->ofs; t->texParams.hwPhysAddress = imesa->savageScreen->textureOffset[heap] + ofs; t->BufAddr = (char *)((GLuint) imesa->savageScreen->texVirtual[heap] + ofs); imesa->dirty |= SAVAGE_UPLOAD_CTX; } /* Let the world know we've used this memory recently. */ savageUpdateTexLRU( imesa, t ); if (t->dirty_images) { if (SAVAGE_DEBUG & DEBUG_VERBOSE_LRU) fprintf(stderr, "*"); for (i = t->min_level ; i <= t->max_level ; i++) if (t->dirty_images & (1<dirty_images = 0; return 0; } static void savageTexSetUnit( savageTextureObjectPtr t, GLuint unit ) { if (t->current_unit == unit) return; t->current_unit = unit; } static void savageUpdateTex0State_s4( GLcontext *ctx ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); struct gl_texture_object *tObj; savageTextureObjectPtr t; GLuint format; /* disable */ if (ctx->Texture.Unit[0]._ReallyEnabled == 0) { imesa->regs.s4.texDescr.ni.tex0En = GL_FALSE; imesa->regs.s4.texBlendCtrl[0].ui = TBC_NoTexMap; imesa->regs.s4.texCtrl[0].ui = 0x20f040; imesa->regs.s4.texAddr[0].ui = 0; return; } tObj = ctx->Texture.Unit[0]._Current; if (ctx->Texture.Unit[0]._ReallyEnabled != TEXTURE_2D_BIT || tObj->Image[0][tObj->BaseLevel]->Border > 0) { /* 1D or 3D texturing enabled, or texture border - fallback */ FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); return; } /* Do 2D texture setup */ t = tObj->DriverData; if (!t) { t = savageAllocTexObj( tObj ); if (!t) return; } if (t->current_unit != 0) savageTexSetUnit( t, 0 ); imesa->CurrentTexObj[0] = t; t->bound |= 1; if (t->dirty_images) { savageSetTexImages(imesa, tObj); savageUploadTexImages(imesa, imesa->CurrentTexObj[0]); } if (t->MemBlock) savageUpdateTexLRU( imesa, t ); format = tObj->Image[0][tObj->BaseLevel]->Format; switch (ctx->Texture.Unit[0].EnvMode) { case GL_REPLACE: imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; switch(format) { case GL_LUMINANCE: case GL_RGB: imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal; break; case GL_LUMINANCE_ALPHA: case GL_RGBA: case GL_INTENSITY: imesa->regs.s4.texBlendCtrl[0].ui = TBC_Copy; break; case GL_ALPHA: imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha; break; } __HWEnvCombineSingleUnitScale(imesa, 0, 0, &imesa->regs.s4.texBlendCtrl[0]); break; case GL_DECAL: imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; switch (format) { case GL_RGB: case GL_LUMINANCE: imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal; break; case GL_RGBA: case GL_INTENSITY: case GL_LUMINANCE_ALPHA: imesa->regs.s4.texBlendCtrl[0].ui = TBC_DecalAlpha; break; /* GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY are undefined with GL_DECAL */ case GL_ALPHA: imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha; break; } __HWEnvCombineSingleUnitScale(imesa, 0, 0, &imesa->regs.s4.texBlendCtrl[0]); break; case GL_MODULATE: imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha; __HWEnvCombineSingleUnitScale(imesa, 0, 0, &imesa->regs.s4.texBlendCtrl[0]); break; case GL_BLEND: switch (format) { case GL_ALPHA: imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha; imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; break; case GL_LUMINANCE: case GL_RGB: imesa->regs.s4.texBlendCtrl[0].ui = TBC_Blend0; imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; imesa->regs.s4.texDescr.ni.tex1Width = imesa->regs.s4.texDescr.ni.tex0Width; imesa->regs.s4.texDescr.ni.tex1Height = imesa->regs.s4.texDescr.ni.tex0Height; imesa->regs.s4.texDescr.ni.tex1Fmt = imesa->regs.s4.texDescr.ni.tex0Fmt; imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui; imesa->regs.s4.texBlendCtrl[1].ui = TBC_Blend1; imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE; imesa->bTexEn1 = GL_TRUE; break; case GL_LUMINANCE_ALPHA: case GL_RGBA: imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendAlpha0; imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; imesa->regs.s4.texDescr.ni.tex1Width = imesa->regs.s4.texDescr.ni.tex0Width; imesa->regs.s4.texDescr.ni.tex1Height = imesa->regs.s4.texDescr.ni.tex0Height; imesa->regs.s4.texDescr.ni.tex1Fmt = imesa->regs.s4.texDescr.ni.tex0Fmt; imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui; imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendAlpha1; imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE; imesa->bTexEn1 = GL_TRUE; break; case GL_INTENSITY: imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendInt0; imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; imesa->regs.s4.texDescr.ni.tex1Width = imesa->regs.s4.texDescr.ni.tex0Width; imesa->regs.s4.texDescr.ni.tex1Height = imesa->regs.s4.texDescr.ni.tex0Height; imesa->regs.s4.texDescr.ni.tex1Fmt = imesa->regs.s4.texDescr.ni.tex0Fmt; imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui; imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendInt1; imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE; imesa->regs.s4.texCtrl[0].ni.alphaArg1Invert = GL_TRUE; imesa->bTexEn1 = GL_TRUE; break; } __HWEnvCombineSingleUnitScale(imesa, 0, 0, &imesa->regs.s4.texBlendCtrl[0]); break; /* GL_ADD */ case GL_ADD: printf("Add\n"); imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE; imesa->regs.s4.texBlendCtrl[0].ui = TBC_AddAlpha; __HWEnvCombineSingleUnitScale(imesa, 0, 0, &imesa->regs.s4.texBlendCtrl[0]); break; #if GL_ARB_texture_env_combine case GL_COMBINE_ARB: __HWParseTexEnvCombine(imesa, 0, &imesa->regs.s4.texCtrl[0], &imesa->regs.s4.texBlendCtrl[0]); break; #endif default: fprintf(stderr, "unknown tex env mode"); exit(1); break; } imesa->regs.s4.texCtrl[0].ni.uMode = !(t->texParams.sWrapMode & 0x01); imesa->regs.s4.texCtrl[0].ni.vMode = !(t->texParams.tWrapMode & 0x01); switch (t->texParams.minFilter) { case GL_NEAREST: imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Point; imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_FALSE; break; case GL_LINEAR: imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Bilin; imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_FALSE; break; case GL_NEAREST_MIPMAP_NEAREST: imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Point; imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE; break; case GL_LINEAR_MIPMAP_NEAREST: imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Bilin; imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE; break; case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: imesa->regs.s4.texCtrl[0].ni.filterMode = TFM_Trilin; imesa->regs.s4.texCtrl[0].ni.mipmapEnable = GL_TRUE; break; } if((ctx->Texture.Unit[0].LodBias !=0.0F) && (imesa->regs.s4.texCtrl[0].ni.dBias != 0)) { union { GLfloat f; GLint i; } bias; GLuint ul; bias.f = ctx->Texture.Unit[0].LodBias; /* if the value is >= 15.9375 determine whether >= 16 or <0 */ if(((bias.i) & 0x7FFFFFFF) >= 0x417F0000) { if((bias.i) & 0x80000000) { ul=0x101; } else { ul=0xff; } } else { ul=(GLuint)(bias.f*16.0); } ul &= 0x1FF; imesa->regs.s4.texCtrl[0].ni.dBias = ul; } imesa->regs.s4.texDescr.ni.tex0En = GL_TRUE; imesa->regs.s4.texDescr.ni.tex0Width = t->image[0].image->WidthLog2; imesa->regs.s4.texDescr.ni.tex0Height = t->image[0].image->HeightLog2; imesa->regs.s4.texDescr.ni.tex0Fmt = t->image[0].internalFormat; imesa->regs.s4.texCtrl[0].ni.dMax = t->max_level; if (imesa->regs.s4.texDescr.ni.tex1En) imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; imesa->regs.s4.texAddr[0].ui = (GLuint) t->texParams.hwPhysAddress | 0x2; if(t->heap == SAVAGE_AGP_HEAP) imesa->regs.s4.texAddr[0].ui |= 0x1; return; } static void savageUpdateTex1State_s4( GLcontext *ctx ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); struct gl_texture_object *tObj; savageTextureObjectPtr t; GLuint format; /* disable */ if(imesa->bTexEn1) { imesa->bTexEn1 = GL_FALSE; return; } if (ctx->Texture.Unit[1]._ReallyEnabled == 0) { imesa->regs.s4.texDescr.ni.tex1En = GL_FALSE; imesa->regs.s4.texBlendCtrl[1].ui = TBC_NoTexMap1; imesa->regs.s4.texCtrl[1].ui = 0x20f040; imesa->regs.s4.texAddr[1].ui = 0; imesa->regs.s4.texDescr.ni.texBLoopEn = GL_FALSE; return; } tObj = ctx->Texture.Unit[1]._Current; if (ctx->Texture.Unit[1]._ReallyEnabled != TEXTURE_2D_BIT || tObj->Image[0][tObj->BaseLevel]->Border > 0) { /* 1D or 3D texturing enabled, or texture border - fallback */ FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); return; } /* Do 2D texture setup */ t = tObj->DriverData; if (!t) { t = savageAllocTexObj( tObj ); if (!t) return; } if (t->current_unit != 1) savageTexSetUnit( t, 1 ); imesa->CurrentTexObj[1] = t; t->bound |= 2; if (t->dirty_images) { savageSetTexImages(imesa, tObj); savageUploadTexImages(imesa, imesa->CurrentTexObj[1]); } if (t->MemBlock) savageUpdateTexLRU( imesa, t ); format = tObj->Image[0][tObj->BaseLevel]->Format; switch (ctx->Texture.Unit[1].EnvMode) { case GL_REPLACE: imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; switch (format) { case GL_LUMINANCE: case GL_RGB: imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal; break; case GL_LUMINANCE_ALPHA: case GL_INTENSITY: case GL_RGBA: imesa->regs.s4.texBlendCtrl[1].ui = TBC_Copy; break; case GL_ALPHA: imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1; break; } __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); break; case GL_MODULATE: imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; imesa->regs.s4.texBlendCtrl[1].ui = TBC_ModulAlpha1; __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); break; /*#if GL_EXT_texture_env_add*/ case GL_ADD: imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; imesa->regs.s4.texBlendCtrl[1].ui = TBC_AddAlpha1; __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); break; /*#endif*/ #if GL_ARB_texture_env_combine case GL_COMBINE_ARB: __HWParseTexEnvCombine(imesa, 1, &texCtrl, &imesa->regs.s4.texBlendCtrl); break; #endif case GL_DECAL: imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE; switch (format) { case GL_LUMINANCE: case GL_RGB: imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal1; break; case GL_LUMINANCE_ALPHA: case GL_INTENSITY: case GL_RGBA: imesa->regs.s4.texBlendCtrl[1].ui = TBC_DecalAlpha1; break; /* // GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY // are undefined with GL_DECAL */ case GL_ALPHA: imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1; break; } __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); break; case GL_BLEND: if (format == GL_LUMINANCE) { /* // This is a hack for GLQuake, invert. */ imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_TRUE; imesa->regs.s4.texBlendCtrl[1].ui = 0; } __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl); break; default: fprintf(stderr, "unkown tex 1 env mode\n"); exit(1); break; } imesa->regs.s4.texCtrl[1].ni.uMode = !(t->texParams.sWrapMode & 0x01); imesa->regs.s4.texCtrl[1].ni.vMode = !(t->texParams.tWrapMode & 0x01); switch (t->texParams.minFilter) { case GL_NEAREST: imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Point; imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_FALSE; break; case GL_LINEAR: imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Bilin; imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_FALSE; break; case GL_NEAREST_MIPMAP_NEAREST: imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Point; imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE; break; case GL_LINEAR_MIPMAP_NEAREST: imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Bilin; imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE; break; case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: imesa->regs.s4.texCtrl[1].ni.filterMode = TFM_Trilin; imesa->regs.s4.texCtrl[1].ni.mipmapEnable = GL_TRUE; break; } if((ctx->Texture.Unit[1].LodBias !=0.0F)&& (imesa->regs.s4.texCtrl[1].ni.dBias != 0)) { union { GLfloat f; GLint i; } bias; GLuint ul; bias.f = ctx->Texture.Unit[1].LodBias; /* if the value is >= 15.9375 determine whether >= 16 or <0 */ if(((bias.i) & 0x7FFFFFFF) >= 0x417F0000) { if((bias.i) & 0x80000000) { ul=0x101; } else { ul=0xff; } } else { ul=(GLuint)(bias.f*16.0); } ul &= 0x1FF; imesa->regs.s4.texCtrl[1].ni.dBias = ul; } imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE; imesa->regs.s4.texDescr.ni.tex1Width = t->image[0].image->WidthLog2; imesa->regs.s4.texDescr.ni.tex1Height = t->image[0].image->HeightLog2; imesa->regs.s4.texDescr.ni.tex1Fmt = t->image[0].internalFormat; imesa->regs.s4.texCtrl[1].ni.dMax = t->max_level; imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE; imesa->regs.s4.texAddr[1].ui = (GLuint) t->texParams.hwPhysAddress| 2; if(t->heap == SAVAGE_AGP_HEAP) imesa->regs.s4.texAddr[1].ui |= 0x1; } static void savageUpdateTexState_s3d( GLcontext *ctx ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); struct gl_texture_object *tObj; savageTextureObjectPtr t; GLuint format; /* disable */ if (ctx->Texture.Unit[0]._ReallyEnabled == 0) { imesa->regs.s3d.texCtrl.ui = 0; imesa->regs.s3d.texCtrl.ni.texEn = GL_FALSE; imesa->regs.s3d.texCtrl.ni.dBias = 0x08; imesa->regs.s3d.texCtrl.ni.texXprEn = GL_TRUE; imesa->regs.s3d.texAddr.ui = 0; return; } tObj = ctx->Texture.Unit[0]._Current; if (ctx->Texture.Unit[0]._ReallyEnabled != TEXTURE_2D_BIT || tObj->Image[0][tObj->BaseLevel]->Border > 0) { /* 1D or 3D texturing enabled, or texture border - fallback */ FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); return; } /* Do 2D texture setup */ t = tObj->DriverData; if (!t) { t = savageAllocTexObj( tObj ); if (!t) return; } if (t->current_unit != 0) savageTexSetUnit( t, 0 ); imesa->CurrentTexObj[0] = t; t->bound |= 1; if (t->dirty_images) { savageSetTexImages(imesa, tObj); savageUploadTexImages(imesa, imesa->CurrentTexObj[0]); } if (t->MemBlock) savageUpdateTexLRU( imesa, t ); format = tObj->Image[0][tObj->BaseLevel]->Format; /* FIXME: copied from utah-glx, probably needs some tuning */ switch (ctx->Texture.Unit[0].EnvMode) { case GL_DECAL: imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECAL_S3D; break; case GL_REPLACE: imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_COPY_S3D; break; case GL_BLEND: /* FIXIT */ case GL_MODULATE: imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_MODULATEALPHA_S3D; break; default: fprintf(stderr, "unkown tex env mode\n"); /*exit(1);*/ break; } imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE; imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites = GL_TRUE; /* FIXME: this is how the utah-driver works. I doubt it's the ultimate truth. */ imesa->regs.s3d.texCtrl.ni.uWrapEn = 0; imesa->regs.s3d.texCtrl.ni.vWrapEn = 0; if (t->texParams.sWrapMode == GL_CLAMP) imesa->regs.s3d.texCtrl.ni.wrapMode = TAM_Clamp; else imesa->regs.s3d.texCtrl.ni.wrapMode = TAM_Wrap; switch (t->texParams.minFilter) { case GL_NEAREST: imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point; imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE; break; case GL_LINEAR: imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin; imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE; break; case GL_NEAREST_MIPMAP_NEAREST: imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point; imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE; break; case GL_LINEAR_MIPMAP_NEAREST: imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin; imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE; break; case GL_NEAREST_MIPMAP_LINEAR: case GL_LINEAR_MIPMAP_LINEAR: imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Trilin; imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE; break; } /* There is no way to specify a maximum mipmap level. We may have to disable mipmapping completely. */ /* if (t->max_level < t->image[0].image->WidthLog2 || t->max_level < t->image[0].image->HeightLog2) { texCtrl.ni.mipmapEnable = GL_TRUE; if (texCtrl.ni.filterMode == TFM_Trilin) texCtrl.ni.filterMode = TFM_Bilin; texCtrl.ni.filterMode = TFM_Point; } */ /* LOD bias makes corruption of small mipmap levels worse on Savage IX * but doesn't show the desired effect with the lodbias mesa demo. */ imesa->regs.s3d.texCtrl.ni.dBias = 0; imesa->regs.s3d.texCtrl.ni.texEn = GL_TRUE; imesa->regs.s3d.texDescr.ni.texWidth = t->image[0].image->WidthLog2; imesa->regs.s3d.texDescr.ni.texHeight = t->image[0].image->HeightLog2; assert (t->image[0].internalFormat <= 7); imesa->regs.s3d.texDescr.ni.texFmt = t->image[0].internalFormat; imesa->regs.s3d.texAddr.ni.addr = (GLuint) t->texParams.hwPhysAddress >> 3; if(t->heap == SAVAGE_AGP_HEAP) { imesa->regs.s3d.texAddr.ni.inSysTex = 1; imesa->regs.s3d.texAddr.ni.inAGPTex = 1; } else { imesa->regs.s3d.texAddr.ni.inSysTex = 0; imesa->regs.s3d.texAddr.ni.inAGPTex = 1; } } static void savageUpdateTextureState_s4( GLcontext *ctx ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1; if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->bound &= ~2; imesa->CurrentTexObj[0] = 0; imesa->CurrentTexObj[1] = 0; FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE); savageUpdateTex0State_s4( ctx ); savageUpdateTex1State_s4( ctx ); imesa->dirty |= (SAVAGE_UPLOAD_CTX | SAVAGE_UPLOAD_TEX0 | SAVAGE_UPLOAD_TEX1); } static void savageUpdateTextureState_s3d( GLcontext *ctx ) { savageContextPtr imesa = SAVAGE_CONTEXT(ctx); if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1; imesa->CurrentTexObj[0] = 0; if (ctx->Texture.Unit[1]._ReallyEnabled) { FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE); } else { FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE); savageUpdateTexState_s3d( ctx ); imesa->dirty |= (SAVAGE_UPLOAD_CTX | SAVAGE_UPLOAD_TEX0); } } static void savageUpdateTextureState_first( GLcontext *ctx) { savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); if (imesa->savageScreen->chipset <= S3_SAVAGE4) { GetTiledCoordinates16 = GetTiledCoordinates16_4; GetTiledCoordinates32 = GetTiledCoordinates32_4; } else { GetTiledCoordinates16 = GetTiledCoordinates16_8; GetTiledCoordinates32 = GetTiledCoordinates32_8; } if (imesa->savageScreen->chipset >= S3_SAVAGE4) savageUpdateTextureState = savageUpdateTextureState_s4; else savageUpdateTextureState = savageUpdateTextureState_s3d; savageUpdateTextureState (ctx); } void (*savageUpdateTextureState)( GLcontext *ctx ) = savageUpdateTextureState_first; /***************************************** * DRIVER functions *****************************************/ static void savageTexEnv( GLcontext *ctx, GLenum target, GLenum pname, const GLfloat *param ) { savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); if (pname == GL_TEXTURE_ENV_MODE) { imesa->new_state |= SAVAGE_NEW_TEXTURE; } else if (pname == GL_TEXTURE_ENV_COLOR) { struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; const GLfloat *fc = texUnit->EnvColor; GLuint r, g, b, a, col; CLAMPED_FLOAT_TO_UBYTE(r, fc[0]); CLAMPED_FLOAT_TO_UBYTE(g, fc[1]); CLAMPED_FLOAT_TO_UBYTE(b, fc[2]); CLAMPED_FLOAT_TO_UBYTE(a, fc[3]); col = ((a << 24) | (r << 16) | (g << 8) | (b << 0)); } } static void savageTexImage2D( GLcontext *ctx, GLenum target, GLint level, GLint internalFormat, GLint width, GLint height, GLint border, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *packing, struct gl_texture_object *texObj, struct gl_texture_image *texImage ) { savageTextureObjectPtr t = (savageTextureObjectPtr) texObj->DriverData; if (t) { savageSwapOutTexObj( SAVAGE_CONTEXT(ctx), t ); } else { t = savageAllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); return; } } _mesa_store_teximage2d( ctx, target, level, internalFormat, width, height, border, format, type, pixels, packing, texObj, texImage ); t->dirty_images |= (1 << level); SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; } static void savageTexSubImage2D( GLcontext *ctx, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *packing, struct gl_texture_object *texObj, struct gl_texture_image *texImage ) { savageTextureObjectPtr t = (savageTextureObjectPtr) texObj->DriverData; assert( t ); /* this _should_ be true */ if (t) { savageSwapOutTexObj( SAVAGE_CONTEXT(ctx), t ); } else { t = savageAllocTexObj(texObj); if (!t) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); return; } } _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, height, format, type, pixels, packing, texObj, texImage); t->dirty_images |= (1 << level); SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE; } static void savageTexParameter( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLenum pname, const GLfloat *params ) { savageTextureObjectPtr t = (savageTextureObjectPtr) tObj->DriverData; savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); if (!t || target != GL_TEXTURE_2D) return; switch (pname) { case GL_TEXTURE_MIN_FILTER: case GL_TEXTURE_MAG_FILTER: savageSetTexFilter(t,tObj->MinFilter,tObj->MagFilter); break; case GL_TEXTURE_WRAP_S: case GL_TEXTURE_WRAP_T: savageSetTexWrapping(t,tObj->WrapS,tObj->WrapT); break; case GL_TEXTURE_BORDER_COLOR: savageSetTexBorderColor(t,tObj->_BorderChan); break; default: return; } imesa->new_state |= SAVAGE_NEW_TEXTURE; } static void savageBindTexture( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj ) { savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); assert( (target != GL_TEXTURE_2D) || (tObj->DriverData != NULL) ); imesa->new_state |= SAVAGE_NEW_TEXTURE; } static void savageDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj ) { savageTextureObjectPtr t = (savageTextureObjectPtr)tObj->DriverData; savageContextPtr imesa = SAVAGE_CONTEXT( ctx ); if (t) { if (t->bound) { imesa->CurrentTexObj[t->bound-1] = 0; imesa->new_state |= SAVAGE_NEW_TEXTURE; } savageDestroyTexObj(imesa,t); tObj->DriverData=0; } /* Free mipmap images and the texture object itself */ _mesa_delete_texture_object(ctx, tObj); } static GLboolean savageIsTextureResident( GLcontext *ctx, struct gl_texture_object *t ) { savageTextureObjectPtr mt; /* LOCK_HARDWARE; */ mt = (savageTextureObjectPtr)t->DriverData; /* UNLOCK_HARDWARE; */ return mt && mt->MemBlock; } static struct gl_texture_object * savageNewTextureObject( GLcontext *ctx, GLuint name, GLenum target ) { struct gl_texture_object *obj; obj = _mesa_new_texture_object(ctx, name, target); savageAllocTexObj( obj ); return obj; } void savageDDInitTextureFuncs( struct dd_function_table *functions ) { functions->TexEnv = savageTexEnv; functions->ChooseTextureFormat = savageChooseTextureFormat; functions->TexImage2D = savageTexImage2D; functions->TexSubImage2D = savageTexSubImage2D; functions->BindTexture = savageBindTexture; functions->NewTextureObject = savageNewTextureObject; functions->DeleteTexture = savageDeleteTexture; functions->IsTextureResident = savageIsTextureResident; functions->TexParameter = savageTexParameter; }