/* -*- mode: c; c-basic-offset: 3 -*- * * Copyright 2000 VA Linux Systems Inc., Fremont, California. * * 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, sublicense, * 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 NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS 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. */ /* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_tex.c,v 1.3 2001/08/18 02:51:07 dawes Exp $ */ /* * Original rewrite: * Gareth Hughes , 29 Sep - 1 Oct 2000 * * Authors: * Gareth Hughes * Brian Paul * */ #include "tdfx_context.h" #include "tdfx_tex.h" #include "tdfx_texman.h" #include "enums.h" #include "image.h" #include "texutil.h" #define TX_DITHER_NONE 0x00000000 static int logbase2( int n ) { GLint i = 1; GLint log2 = 0; if ( n < 0 ) return -1; while ( n > i ) { i *= 2; log2++; } if ( i != n ) { return -1; } else { return log2; } } /* Compute various texture image parameters. * Input: w, h - source texture width and height * Output: lodlevel - Glide lod level token for the larger texture dimension * aspectratio - Glide aspect ratio token * sscale - S scale factor used during triangle setup * tscale - T scale factor used during triangle setup * wscale - OpenGL -> Glide image width scale factor * hscale - OpenGL -> Glide image height scale factor * * Sample results: * w h lodlevel aspectRatio * 128 128 GR_LOD_LOG2_128 (=7) GR_ASPECT_LOG2_1x1 (=0) * 64 64 GR_LOD_LOG2_64 (=6) GR_ASPECT_LOG2_1x1 (=0) * 64 32 GR_LOD_LOG2_64 (=6) GR_ASPECT_LOG2_2x1 (=1) * 32 64 GR_LOD_LOG2_64 (=6) GR_ASPECT_LOG2_1x2 (=-1) * 32 32 GR_LOD_LOG2_32 (=5) GR_ASPECT_LOG2_1x1 (=0) */ static void tdfxTexGetInfo( const GLcontext *ctx, int w, int h, GrLOD_t *lodlevel, GrAspectRatio_t *aspectratio, float *sscale, float *tscale, int *wscale, int *hscale ) { int logw, logh, ar, lod, ws, hs; float s, t; ASSERT( w >= 1 ); ASSERT( h >= 1 ); logw = logbase2( w ); logh = logbase2( h ); ar = logw - logh; /* aspect ratio = difference in log dimensions */ /* Hardware only allows a maximum aspect ratio of 8x1, so handle * |ar| > 3 by scaling the image and using an 8x1 aspect ratio. */ if ( ar >= 0 ) { ASSERT( w >= h ); lod = logw; s = 256.0; ws = 1; if ( ar <= GR_ASPECT_LOG2_8x1 ) { t = 256 >> ar; hs = 1; } else { /* have to stretch image height */ t = 32.0; hs = 1 << (ar - 3); } } else { ASSERT( w < h ); lod = logh; t = 256.0; hs = 1; if ( ar >= GR_ASPECT_LOG2_1x8 ) { s = 256 >> -ar; ws = 1; } else { /* have to stretch image width */ s = 32.0; ws = 1 << (-ar - 3); } } if ( ar < GR_ASPECT_LOG2_1x8 ) { ar = GR_ASPECT_LOG2_1x8; } else if ( ar > GR_ASPECT_LOG2_8x1 ) { ar = GR_ASPECT_LOG2_8x1; } if ( lodlevel ) *lodlevel = (GrLOD_t)lod; if ( aspectratio ) *aspectratio = (GrAspectRatio_t)ar; if ( sscale ) *sscale = s; if ( tscale ) *tscale = t; if ( wscale ) *wscale = ws; if ( hscale ) *hscale = hs; } /* We need to call this when a texture object's minification filter * or texture image sizes change. */ static void tdfxRevalidateTexture( GLcontext *ctx, struct gl_texture_object *tObj ) { tdfxTexObjPtr t = TDFX_TEXTURE_DATA(tObj); GLint minl, maxl; if ( !t ) return; minl = maxl = tObj->BaseLevel; if ( tObj->Image[minl] ) { maxl = MIN2( tObj->MaxLevel, tObj->Image[minl]->MaxLog2 ); /* Compute largeLodLog2, aspect ratio and texcoord scale factors. */ tdfxTexGetInfo( ctx, tObj->Image[minl]->Width, tObj->Image[minl]->Height, &t->info.largeLodLog2, &t->info.aspectRatioLog2, &t->sScale, &t->tScale, NULL, NULL ); } if ( tObj->Image[maxl] && tObj->MinFilter != GL_NEAREST && tObj->MinFilter != GL_LINEAR ) { /* Mipmapping: need to compute smallLodLog2 */ tdfxTexGetInfo( ctx, tObj->Image[maxl]->Width, tObj->Image[maxl]->Height, &t->info.smallLodLog2, NULL, NULL, NULL, NULL, NULL ); } else { /* Not mipmapping: smallLodLog2 = largeLodLog2 */ t->info.smallLodLog2 = t->info.largeLodLog2; } t->minLevel = minl; t->maxLevel = maxl; t->info.data = NULL; } static tdfxTexObjPtr tdfxAllocTexObj( tdfxContextPtr fxMesa ) { tdfxTexObjPtr t; int i; t = CALLOC( sizeof(tdfxTexObj) ); if ( !t ) { gl_problem( NULL, "tdfx driver: out of memory" ); return NULL; } t->isInTM = GL_FALSE; t->whichTMU = TDFX_TMU_NONE; t->range[TDFX_TMU0] = NULL; t->range[TDFX_TMU1] = NULL; t->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED; t->magFilt = GR_TEXTUREFILTER_BILINEAR; t->sClamp = GR_TEXTURECLAMP_WRAP; t->tClamp = GR_TEXTURECLAMP_WRAP; t->mmMode = GR_MIPMAP_NEAREST; t->LODblend = FXFALSE; for ( i = 0 ; i < MAX_TEXTURE_LEVELS ; i++ ) { t->image[i].original.data = NULL; t->image[i].rescaled.data = NULL; } return t; } /* Given an OpenGL internal texture format, return the corresponding * Glide internal texture format and MesaIntTexFormat. * If allow32bpp is true, we'll return 32-bit texel formats when * appropriate. */ static GrTextureFormat_t tdfxTexGetFormat( tdfxContextPtr fxMesa, struct gl_texture_image *texImage, GLenum format, GLenum type ) { const GLboolean allow32bpp = TDFX_IS_NAPALM(fxMesa); const GLboolean is32bpp = ( fxMesa->fxScreen->cpp == 4 ); const struct gl_texture_format *texFormat; GrTextureFormat_t ret; if ( 0 ) fprintf( stderr, "internal=%s format=%s type=%s\n", texImage->IntFormat == 3 ? "GL_RGB (3)" : texImage->IntFormat == 4 ? "GL_RGBA (4)" : gl_lookup_enum_by_nr( texImage->IntFormat ), gl_lookup_enum_by_nr( format ), gl_lookup_enum_by_nr( type ) ); #define SET_FORMAT( gr, gl ) \ do { \ ret = (gr); \ texFormat = &(gl); \ } while (0) #define SET_FORMAT_32BPP( gr32, gl32, gr16, gl16 ) \ do { \ if ( allow32bpp ) { \ ret = (gr32); \ texFormat = &(gl32); \ } else { \ ret = (gr16); \ texFormat = &(gl16); \ } \ } while (0) switch ( texImage->IntFormat ) { /* GH: Bias towards GL_RGB, GL_RGBA texture formats. This has * got to be better than sticking them way down the end of this * huge list. */ case GL_RGBA: case 4: if ( format == GL_BGRA ) { if ( type == GL_UNSIGNED_INT_8_8_8_8_REV && allow32bpp ) { SET_FORMAT( GR_TEXFMT_ARGB_8888, _mesa_texformat_argb8888 ); break; } else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { SET_FORMAT( GR_TEXFMT_ARGB_4444, _mesa_texformat_argb4444 ); break; } else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { SET_FORMAT( GR_TEXFMT_ARGB_1555, _mesa_texformat_argb1555 ); break; } } if ( allow32bpp && is32bpp ) { SET_FORMAT( GR_TEXFMT_ARGB_8888, _mesa_texformat_argb8888 ); } else { SET_FORMAT( GR_TEXFMT_ARGB_4444, _mesa_texformat_argb4444 ); } break; case GL_RGB: case 3: if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { SET_FORMAT( GR_TEXFMT_RGB_565, _mesa_texformat_rgb565 ); break; } if ( allow32bpp && is32bpp ) { SET_FORMAT( GR_TEXFMT_ARGB_8888, _mesa_texformat_argb8888 ); } else { SET_FORMAT( GR_TEXFMT_RGB_565, _mesa_texformat_rgb565 ); } break; /* GH: Okay, keep checking as normal. Still test for GL_RGB, * GL_RGBA formats first. */ case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: SET_FORMAT_32BPP( GR_TEXFMT_ARGB_8888, _mesa_texformat_argb8888, GR_TEXFMT_ARGB_4444, _mesa_texformat_argb4444 ); break; case GL_RGBA4: case GL_RGBA2: SET_FORMAT( GR_TEXFMT_ARGB_4444, _mesa_texformat_argb4444 ); break; case GL_RGB5_A1: SET_FORMAT( GR_TEXFMT_ARGB_1555, _mesa_texformat_argb1555 ); break; case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: SET_FORMAT_32BPP( GR_TEXFMT_ARGB_8888, _mesa_texformat_argb8888, GR_TEXFMT_RGB_565, _mesa_texformat_rgb565 ); break; case GL_RGB5: case GL_RGB4: case GL_R3_G3_B2: SET_FORMAT( GR_TEXFMT_RGB_565, _mesa_texformat_rgb565 ); break; case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: SET_FORMAT( GR_TEXFMT_ALPHA_8, _mesa_texformat_a8 ); break; case 1: case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: case GL_LUMINANCE12: case GL_LUMINANCE16: SET_FORMAT( GR_TEXFMT_INTENSITY_8, _mesa_texformat_l8 ); break; case 2: case GL_LUMINANCE_ALPHA: case GL_LUMINANCE4_ALPHA4: case GL_LUMINANCE6_ALPHA2: case GL_LUMINANCE8_ALPHA8: case GL_LUMINANCE12_ALPHA4: case GL_LUMINANCE12_ALPHA12: case GL_LUMINANCE16_ALPHA16: SET_FORMAT( GR_TEXFMT_ALPHA_INTENSITY_88, _mesa_texformat_al88 ); break; case GL_INTENSITY: case GL_INTENSITY4: case GL_INTENSITY8: case GL_INTENSITY12: case GL_INTENSITY16: SET_FORMAT( GR_TEXFMT_ALPHA_8, _mesa_texformat_i8 ); break; 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: SET_FORMAT( GR_TEXFMT_P_8, _mesa_texformat_ci8 ); break; default: fprintf( stderr, "bad texture format in fxTexGetFormat() %d", texImage->IntFormat ); return -1; } texImage->TexFormat = texFormat; return ret; } static GLboolean tdfxDDTexImage2D( GLcontext *ctx, GLenum target, GLint level, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *packing, struct gl_texture_object *texObj, struct gl_texture_image *texImage, GLboolean *retainInternalCopy ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); const struct gl_texture_format *texFormat; GrTextureFormat_t glideFormat; tdfxTexObjPtr t; tdfxTexImagePtr image; GLint dstWidth, dstHeight, wScale, hScale; GLint size; void *data; if ( 0 ) { printf("TexImage id=%d int 0x%x format 0x%x type 0x%x %dx%d\n", texObj->Name, texImage->IntFormat, format, type, texImage->Width, texImage->Height); } if ( target != GL_TEXTURE_2D || texImage->Border > 0 ) return GL_FALSE; if ( !texObj->DriverData ) texObj->DriverData = tdfxAllocTexObj( fxMesa ); t = TDFX_TEXTURE_DATA(texObj); image = &t->image[level]; /* Determine the appropriate GL internal texel format, Mesa internal * texel format, and texelSize (bytes) given the user's internal * texture format hint. */ glideFormat = tdfxTexGetFormat( fxMesa, texImage, format, type ); /* Get the destination internal format. */ texFormat = texImage->TexFormat; /* Determine width and height scale factors for texture. Remember, * Glide is limited to 8:1 aspect ratios. */ tdfxTexGetInfo( ctx, texImage->Width, texImage->Height, NULL, NULL, NULL, NULL, &wScale, &hScale ); dstWidth = texImage->Width * wScale; dstHeight = texImage->Height * hScale; /* Allocate new storage for texture image, if needed. This * conditional wants to set uncompressedImage to point to the * uncompressed image, and mml->data to the texture data. If the * image is uncompressed, these are identical. If the image is not * compressed, these are different. */ if ( !image->original.data || image->glideFormat != glideFormat || image->original.width != texImage->Width || image->original.height != texImage->Height ) { if ( image->original.data ) { FREE( image->original.data ); image->original.data = NULL; } if ( image->rescaled.data ) { FREE( image->rescaled.data ); image->rescaled.data = NULL; } size = texImage->Width * texImage->Height * texFormat->TexelBytes; image->original.data = (void *) MALLOC( size ); if ( !image->original.data ) return GL_FALSE; image->original.width = texImage->Width; image->original.height = texImage->Height; image->original.size = size; image->glideFormat = glideFormat; image->wScale = wScale; image->hScale = hScale; t->info.format = glideFormat; tdfxTMMoveOutTM( fxMesa, texObj ); } /* Store the texture image into the 'original' space. */ if ( !_mesa_convert_texsubimage2d( texFormat->IntFormat, 0, 0, texImage->Width, texImage->Height, texImage->Width, format, type, packing, pixels, image->original.data ) ) { return GL_FALSE; } data = image->original.data; size = image->original.size; /* GH: Sigh... */ if ( wScale > 1 || hScale > 1 ) { if ( image->rescaled.data ) { FREE( image->rescaled.data ); image->rescaled.data = NULL; } size = dstWidth * dstHeight * texFormat->TexelBytes; image->rescaled.data = (void *) MALLOC( size ); if ( !image->rescaled.data ) return GL_FALSE; image->rescaled.width = dstWidth; image->rescaled.height = dstHeight; image->rescaled.size = size; _mesa_rescale_teximage2d( texFormat->TexelBytes, texImage->Width, texImage->Height, dstWidth, dstHeight, image->original.data, image->rescaled.data ); data = image->rescaled.data; } image->data = data; image->size = size; tdfxRevalidateTexture( ctx, texObj ); t->reloadImages = GL_TRUE; fxMesa->new_state |= TDFX_NEW_TEXTURE; *retainInternalCopy = GL_FALSE; return GL_TRUE; } static GLboolean tdfxDDTexSubImage2D( 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 ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxTexObjPtr t = TDFX_TEXTURE_DATA(texObj); tdfxTexImagePtr image; if ( target != GL_TEXTURE_2D ) return GL_FALSE; if ( !t ) return GL_FALSE; if ( 0 ) { fprintf( stderr, "TexSubImage id=%d lvl=%d int=0x%x format=0x%x type=0x%x x=%d y=%d w=%d h=%d fullW=%d fullH=%d\n", texObj->Name, level, texImage->IntFormat, format, type, xoffset, yoffset, width, height, texImage->Width, texImage->Height ); } image = &t->image[level]; /* Must have an existing texture image! */ assert( image->original.data ); if ( !_mesa_convert_texsubimage2d( texImage->TexFormat->IntFormat, xoffset, yoffset, width, height, texImage->Width, format, type, packing, pixels, image->original.data ) ) { return GL_FALSE; } /* Rescale the original image again if we have to. */ if ( image->wScale > 1 || image->hScale > 1 ) { assert( image->rescaled.data ); _mesa_rescale_teximage2d( texImage->TexFormat->TexelBytes, image->original.width, image->original.height, image->rescaled.width, image->rescaled.height, image->original.data, image->rescaled.data ); } t->reloadImages = GL_TRUE; /* signal the image needs to be reloaded */ fxMesa->new_state |= TDFX_NEW_TEXTURE; /* XXX this might be a bit much */ return GL_TRUE; } /* ================================================================ * */ static void tdfxDDTexEnv( GLcontext *ctx, GLenum target, GLenum pname, const GLfloat *param ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) { if ( param ) { fprintf( stderr, __FUNCTION__"( %x, %x )\n", pname, (GLint)(*param) ); } else { fprintf( stderr, __FUNCTION__"( %x )\n", pname ); } } fxMesa->new_state |= TDFX_NEW_TEXTURE; } static void tdfxDDTexParameter( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLenum pname, const GLfloat *params ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); GLenum param = (GLenum) (GLint) params[0]; tdfxTexObjPtr t; if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, __FUNCTION__ "( %d, %p, %x, %x )\n", tObj->Name, tObj->DriverData, pname, param ); } if ( target != GL_TEXTURE_2D ) return; if ( !tObj->DriverData ) tObj->DriverData = tdfxAllocTexObj( fxMesa ); t = TDFX_TEXTURE_DATA(tObj); switch ( pname ) { case GL_TEXTURE_MIN_FILTER: switch ( param ) { case GL_NEAREST: t->mmMode = GR_MIPMAP_DISABLE; t->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED; t->LODblend = FXFALSE; break; case GL_LINEAR: t->mmMode = GR_MIPMAP_DISABLE; t->minFilt = GR_TEXTUREFILTER_BILINEAR; t->LODblend = FXFALSE; break; case GL_NEAREST_MIPMAP_LINEAR: if ( TDFX_IS_NAPALM(fxMesa) ) { if ( fxMesa->numTMUs > 1 ) { t->mmMode = GR_MIPMAP_NEAREST; t->LODblend = FXTRUE; } else { t->mmMode = GR_MIPMAP_NEAREST_DITHER; t->LODblend = FXFALSE; } t->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED; break; } /* XXX Voodoo3/Banshee mipmap blending seems to produce * incorrectly filtered colors for the smallest mipmap levels. * To work-around we fall-through here and use a different filter. */ case GL_NEAREST_MIPMAP_NEAREST: t->mmMode = GR_MIPMAP_NEAREST; t->minFilt = GR_TEXTUREFILTER_POINT_SAMPLED; t->LODblend = FXFALSE; break; case GL_LINEAR_MIPMAP_LINEAR: if ( TDFX_IS_NAPALM(fxMesa) ) { if ( fxMesa->numTMUs > 1 ) { t->mmMode = GR_MIPMAP_NEAREST; t->LODblend = FXTRUE; } else { t->mmMode = GR_MIPMAP_NEAREST_DITHER; t->LODblend = FXFALSE; } t->minFilt = GR_TEXTUREFILTER_BILINEAR; break; } /* XXX Voodoo3/Banshee mipmap blending seems to produce * incorrectly filtered colors for the smallest mipmap levels. * To work-around we fall-through here and use a different filter. */ case GL_LINEAR_MIPMAP_NEAREST: t->mmMode = GR_MIPMAP_NEAREST; t->minFilt = GR_TEXTUREFILTER_BILINEAR; t->LODblend = FXFALSE; break; default: break; } tdfxRevalidateTexture( ctx, tObj ); fxMesa->new_state |= TDFX_NEW_TEXTURE; break; case GL_TEXTURE_MAG_FILTER: switch ( param ) { case GL_NEAREST: t->magFilt = GR_TEXTUREFILTER_POINT_SAMPLED; break; case GL_LINEAR: t->magFilt = GR_TEXTUREFILTER_BILINEAR; break; default: break; } fxMesa->new_state |= TDFX_NEW_TEXTURE; break; case GL_TEXTURE_WRAP_S: switch ( param ) { case GL_CLAMP: t->sClamp = GR_TEXTURECLAMP_CLAMP; break; case GL_REPEAT: t->sClamp = GR_TEXTURECLAMP_WRAP; break; default: break; } fxMesa->new_state |= TDFX_NEW_TEXTURE; break; case GL_TEXTURE_WRAP_T: switch ( param ) { case GL_CLAMP: t->tClamp = GR_TEXTURECLAMP_CLAMP; break; case GL_REPEAT: t->tClamp = GR_TEXTURECLAMP_WRAP; break; default: break; } fxMesa->new_state |= TDFX_NEW_TEXTURE; break; case GL_TEXTURE_BASE_LEVEL: tdfxRevalidateTexture( ctx, tObj ); break; case GL_TEXTURE_MAX_LEVEL: tdfxRevalidateTexture( ctx, tObj ); break; case GL_TEXTURE_BORDER_COLOR: /* TO DO */ break; case GL_TEXTURE_MIN_LOD: /* TO DO */ break; case GL_TEXTURE_MAX_LOD: /* TO DO */ break; default: break; } } static void tdfxDDBindTexture( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxTexObjPtr t; if ( TDFX_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, __FUNCTION__ "( %d, %p )\n", tObj->Name, tObj->DriverData ); } if ( target != GL_TEXTURE_2D ) return; if ( !tObj->DriverData ) tObj->DriverData = tdfxAllocTexObj( fxMesa ); t = TDFX_TEXTURE_DATA(tObj); t->lastTimeUsed = fxMesa->texBindNumber++; fxMesa->new_state |= TDFX_NEW_TEXTURE; } static void tdfxDDDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); if ( fxMesa->driDrawable ) { LOCK_HARDWARE( fxMesa ); tdfxTMFreeTextureLocked( fxMesa, tObj ); UNLOCK_HARDWARE( fxMesa ); } fxMesa->new_state |= TDFX_NEW_TEXTURE; } static GLboolean tdfxDDIsTextureResident( GLcontext *ctx, struct gl_texture_object *tObj ) { tdfxTexObjPtr t = TDFX_TEXTURE_DATA(tObj); return ( t && t->isInTM ); } /* Convert a gl_color_table texture palette to Glide's format. */ static void tdfxConvertPalette( FxU32 data[256], const struct gl_color_table *table ) { const GLubyte *tableUB = (const GLubyte *) table->Table; GLint width = table->Size; FxU32 r, g, b, a; GLint i; ASSERT( table->TableType == GL_UNSIGNED_BYTE ); switch ( table->Format ) { case GL_RGBA: for ( i = 0 ; i < width ; i++ ) { r = tableUB[i * 4 + 0]; g = tableUB[i * 4 + 1]; b = tableUB[i * 4 + 2]; a = tableUB[i * 4 + 3]; data[i] = PACK_COLOR_8888( a, r, g, b ); } break; case GL_RGB: for ( i = 0 ; i < width ; i++ ) { r = tableUB[i * 3 + 0]; g = tableUB[i * 3 + 1]; b = tableUB[i * 3 + 2]; a = 255; data[i] = PACK_COLOR_8888( a, r, g, b ); } break; case GL_LUMINANCE: for ( i = 0 ; i < width ; i++ ) { r = tableUB[i]; g = tableUB[i]; b = tableUB[i]; a = 255; data[i] = PACK_COLOR_8888( a, r, g, b ); } break; case GL_ALPHA: for ( i = 0 ; i < width ; i++ ) { r = g = b = 255; a = tableUB[i]; data[i] = PACK_COLOR_8888( a, r, g, b ); } break; case GL_LUMINANCE_ALPHA: for ( i = 0 ; i < width ; i++ ) { r = g = b = tableUB[i * 2 + 0]; a = tableUB[i * 2 + 1]; data[i] = PACK_COLOR_8888( a, r, g, b ); } break; case GL_INTENSITY: for ( i = 0 ; i < width ; i++ ) { r = tableUB[i]; g = tableUB[i]; b = tableUB[i]; a = tableUB[i]; data[i] = PACK_COLOR_8888( a, r, g, b ); } break; } } static void tdfxDDTexturePalette( GLcontext *ctx, struct gl_texture_object *tObj ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxTexObjPtr t; if ( tObj ) { /* Per-texture palette */ if ( !tObj->DriverData ) tObj->DriverData = tdfxAllocTexObj(fxMesa); t = TDFX_TEXTURE_DATA(tObj); tdfxConvertPalette( t->palette.data, &tObj->Palette ); /*tdfxTexInvalidate( ctx, tObj );*/ } else { /* Global texture palette */ tdfxConvertPalette( fxMesa->glbPalette.data, &ctx->Texture.Palette ); } fxMesa->new_state |= TDFX_NEW_TEXTURE; /* XXX too heavy-handed */ } /**********************************************************************/ /**** NEW TEXTURE IMAGE FUNCTIONS ****/ /**********************************************************************/ #if 0 static void PrintTexture(int w, int h, int c, const GLubyte * data) { int i, j; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { if (c == 2) printf("%02x %02x ", data[0], data[1]); else if (c == 3) printf("%02x %02x %02x ", data[0], data[1], data[2]); data += c; } printf("\n"); } } #endif static GLboolean tdfxDDTestProxyTexImage( GLcontext *ctx, GLenum target, GLint level, GLint internalFormat, GLenum format, GLenum type, GLint width, GLint height, GLint depth, GLint border ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); struct gl_shared_state *ss = fxMesa->glCtx->Shared; tdfxSharedStatePtr tss = (tdfxSharedStatePtr)ss->DriverData; switch (target) { case GL_PROXY_TEXTURE_1D: return GL_TRUE; /* software rendering */ case GL_PROXY_TEXTURE_2D: { struct gl_texture_object *tObj; tdfxTexObjPtr t; int memNeeded; tObj = ctx->Texture.Proxy2D; if (!tObj->DriverData) tObj->DriverData = tdfxAllocTexObj(fxMesa); t = TDFX_TEXTURE_DATA(tObj); /* assign the parameters to test against */ tObj->Image[level]->Width = width; tObj->Image[level]->Height = height; tObj->Image[level]->Border = border; tObj->Image[level]->IntFormat = internalFormat; if (level == 0) { /* don't use mipmap levels > 0 */ tObj->MinFilter = tObj->MagFilter = GL_NEAREST; } else { /* test with all mipmap levels */ tObj->MinFilter = GL_LINEAR_MIPMAP_LINEAR; tObj->MagFilter = GL_NEAREST; } tdfxRevalidateTexture(ctx, tObj); /* printf("small lodlog2 0x%x\n", t->info.smallLodLog2); printf("large lodlog2 0x%x\n", t->info.largeLodLog2); printf("aspect ratio 0x%x\n", t->info.aspectRatioLog2); printf("glide format 0x%x\n", t->info.format); printf("data %p\n", t->info.data); printf("lodblend %d\n", (int) t->LODblend); */ /* determine where texture will reside */ if (t->LODblend && !tss->umaTexMemory) { /* XXX GR_MIPMAPLEVELMASK_BOTH might not be right, but works */ memNeeded = fxMesa->Glide.grTexTextureMemRequired( GR_MIPMAPLEVELMASK_BOTH, &(t->info)); } else { /* XXX GR_MIPMAPLEVELMASK_BOTH might not be right, but works */ memNeeded = fxMesa->Glide.grTexTextureMemRequired( GR_MIPMAPLEVELMASK_BOTH, &(t->info)); } /* printf("Proxy test %d > %d\n", memNeeded, tss->totalTexMem[0]); */ if (memNeeded > tss->totalTexMem[0]) return GL_FALSE; else return GL_TRUE; } case GL_PROXY_TEXTURE_3D: return GL_TRUE; /* software rendering */ default: return GL_TRUE; /* never happens, silence compiler */ } } /* Return a texture image to Mesa. This is either to satisfy * a glGetTexImage() call or to prepare for software texturing. */ static GLvoid * tdfxDDGetTexImage( GLcontext *ctx, GLenum target, GLint level, const struct gl_texture_object *texObj, GLenum *formatOut, GLenum *typeOut, GLboolean *freeImageOut ) { const struct gl_texture_image *texImage = texObj->Image[level]; const struct gl_texture_format *texFormat = texImage->TexFormat; tdfxTexObjPtr t = TDFX_TEXTURE_DATA(texObj); tdfxTexImagePtr image; GLubyte *data; if ( target != GL_TEXTURE_2D ) return NULL; if ( !t ) return NULL; image = &t->image[level]; if ( !image->original.data ) return NULL; data = (GLubyte *) MALLOC( texImage->Width * texImage->Height * 4 ); if ( !data ) return NULL; _mesa_unconvert_teximage2d( texFormat->IntFormat, texImage->Format, texImage->Width, texImage->Height, image->original.data, data ); *formatOut = texImage->Format; *typeOut = GL_UNSIGNED_BYTE; *freeImageOut = GL_TRUE; return data; } void tdfxDDInitTextureFuncs( GLcontext *ctx ) { ctx->Driver.TexImage2D = tdfxDDTexImage2D; ctx->Driver.TexSubImage2D = tdfxDDTexSubImage2D; ctx->Driver.GetTexImage = tdfxDDGetTexImage; ctx->Driver.TexEnv = tdfxDDTexEnv; ctx->Driver.TexParameter = tdfxDDTexParameter; ctx->Driver.BindTexture = tdfxDDBindTexture; ctx->Driver.DeleteTexture = tdfxDDDeleteTexture; ctx->Driver.IsTextureResident = tdfxDDIsTextureResident; ctx->Driver.UpdateTexturePalette = tdfxDDTexturePalette; }