Home | History | Annotate | Download | only in r200
      1 /*
      2 Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
      3 
      4 The Weather Channel (TM) funded Tungsten Graphics to develop the
      5 initial release of the Radeon 8500 driver under the XFree86 license.
      6 This notice must be preserved.
      7 
      8 Permission is hereby granted, free of charge, to any person obtaining
      9 a copy of this software and associated documentation files (the
     10 "Software"), to deal in the Software without restriction, including
     11 without limitation the rights to use, copy, modify, merge, publish,
     12 distribute, sublicense, and/or sell copies of the Software, and to
     13 permit persons to whom the Software is furnished to do so, subject to
     14 the following conditions:
     15 
     16 The above copyright notice and this permission notice (including the
     17 next paragraph) shall be included in all copies or substantial
     18 portions of the Software.
     19 
     20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
     24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     27 */
     28 
     29 /*
     30  * Authors:
     31  *   Keith Whitwell <keith (at) tungstengraphics.com>
     32  */
     33 
     34 #include "main/glheader.h"
     35 #include "main/imports.h"
     36 #include "main/colormac.h"
     37 #include "main/context.h"
     38 #include "main/enums.h"
     39 #include "main/image.h"
     40 #include "main/mfeatures.h"
     41 #include "main/simple_list.h"
     42 #include "main/teximage.h"
     43 #include "main/texobj.h"
     44 #include "main/samplerobj.h"
     45 
     46 #include "radeon_mipmap_tree.h"
     47 #include "r200_context.h"
     48 #include "r200_ioctl.h"
     49 #include "r200_tex.h"
     50 
     51 #include "xmlpool.h"
     52 
     53 
     54 
     55 /**
     56  * Set the texture wrap modes.
     57  *
     58  * \param t Texture object whose wrap modes are to be set
     59  * \param swrap Wrap mode for the \a s texture coordinate
     60  * \param twrap Wrap mode for the \a t texture coordinate
     61  */
     62 
     63 static void r200SetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap, GLenum rwrap )
     64 {
     65    GLboolean  is_clamp = GL_FALSE;
     66    GLboolean  is_clamp_to_border = GL_FALSE;
     67    struct gl_texture_object *tObj = &t->base;
     68 
     69    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
     70 		"%s(tex %p) sw %s, tw %s, rw %s\n",
     71 		__func__, t,
     72 		_mesa_lookup_enum_by_nr(swrap),
     73 		_mesa_lookup_enum_by_nr(twrap),
     74 		_mesa_lookup_enum_by_nr(rwrap));
     75 
     76    t->pp_txfilter &= ~(R200_CLAMP_S_MASK | R200_CLAMP_T_MASK | R200_BORDER_MODE_D3D);
     77 
     78    switch ( swrap ) {
     79    case GL_REPEAT:
     80       t->pp_txfilter |= R200_CLAMP_S_WRAP;
     81       break;
     82    case GL_CLAMP:
     83       t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
     84       is_clamp = GL_TRUE;
     85       break;
     86    case GL_CLAMP_TO_EDGE:
     87       t->pp_txfilter |= R200_CLAMP_S_CLAMP_LAST;
     88       break;
     89    case GL_CLAMP_TO_BORDER:
     90       t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
     91       is_clamp_to_border = GL_TRUE;
     92       break;
     93    case GL_MIRRORED_REPEAT:
     94       t->pp_txfilter |= R200_CLAMP_S_MIRROR;
     95       break;
     96    case GL_MIRROR_CLAMP_EXT:
     97       t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
     98       is_clamp = GL_TRUE;
     99       break;
    100    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
    101       t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_LAST;
    102       break;
    103    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
    104       t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
    105       is_clamp_to_border = GL_TRUE;
    106       break;
    107    default:
    108       _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
    109    }
    110 
    111    if (tObj->Target != GL_TEXTURE_1D) {
    112       switch ( twrap ) {
    113       case GL_REPEAT:
    114          t->pp_txfilter |= R200_CLAMP_T_WRAP;
    115          break;
    116       case GL_CLAMP:
    117          t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
    118          is_clamp = GL_TRUE;
    119          break;
    120       case GL_CLAMP_TO_EDGE:
    121          t->pp_txfilter |= R200_CLAMP_T_CLAMP_LAST;
    122          break;
    123       case GL_CLAMP_TO_BORDER:
    124          t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
    125          is_clamp_to_border = GL_TRUE;
    126          break;
    127       case GL_MIRRORED_REPEAT:
    128          t->pp_txfilter |= R200_CLAMP_T_MIRROR;
    129          break;
    130       case GL_MIRROR_CLAMP_EXT:
    131          t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
    132          is_clamp = GL_TRUE;
    133          break;
    134       case GL_MIRROR_CLAMP_TO_EDGE_EXT:
    135          t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_LAST;
    136          break;
    137       case GL_MIRROR_CLAMP_TO_BORDER_EXT:
    138          t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
    139          is_clamp_to_border = GL_TRUE;
    140          break;
    141       default:
    142          _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
    143       }
    144    }
    145 
    146    t->pp_txformat_x &= ~R200_CLAMP_Q_MASK;
    147 
    148    switch ( rwrap ) {
    149    case GL_REPEAT:
    150       t->pp_txformat_x |= R200_CLAMP_Q_WRAP;
    151       break;
    152    case GL_CLAMP:
    153       t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
    154       is_clamp = GL_TRUE;
    155       break;
    156    case GL_CLAMP_TO_EDGE:
    157       t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_LAST;
    158       break;
    159    case GL_CLAMP_TO_BORDER:
    160       t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
    161       is_clamp_to_border = GL_TRUE;
    162       break;
    163    case GL_MIRRORED_REPEAT:
    164       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR;
    165       break;
    166    case GL_MIRROR_CLAMP_EXT:
    167       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
    168       is_clamp = GL_TRUE;
    169       break;
    170    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
    171       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_LAST;
    172       break;
    173    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
    174       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
    175       is_clamp_to_border = GL_TRUE;
    176       break;
    177    default:
    178       _mesa_problem(NULL, "bad R wrap mode in %s", __FUNCTION__);
    179    }
    180 
    181    if ( is_clamp_to_border ) {
    182       t->pp_txfilter |= R200_BORDER_MODE_D3D;
    183    }
    184 
    185    t->border_fallback = (is_clamp && is_clamp_to_border);
    186 }
    187 
    188 static void r200SetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
    189 {
    190    t->pp_txfilter &= ~R200_MAX_ANISO_MASK;
    191    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
    192 	"%s(tex %p) max %f.\n",
    193 	__func__, t, max);
    194 
    195    if ( max <= 1.0 ) {
    196       t->pp_txfilter |= R200_MAX_ANISO_1_TO_1;
    197    } else if ( max <= 2.0 ) {
    198       t->pp_txfilter |= R200_MAX_ANISO_2_TO_1;
    199    } else if ( max <= 4.0 ) {
    200       t->pp_txfilter |= R200_MAX_ANISO_4_TO_1;
    201    } else if ( max <= 8.0 ) {
    202       t->pp_txfilter |= R200_MAX_ANISO_8_TO_1;
    203    } else {
    204       t->pp_txfilter |= R200_MAX_ANISO_16_TO_1;
    205    }
    206 }
    207 
    208 /**
    209  * Set the texture magnification and minification modes.
    210  *
    211  * \param t Texture whose filter modes are to be set
    212  * \param minf Texture minification mode
    213  * \param magf Texture magnification mode
    214  */
    215 
    216 static void r200SetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
    217 {
    218    GLuint anisotropy = (t->pp_txfilter & R200_MAX_ANISO_MASK);
    219 
    220    /* Force revalidation to account for switches from/to mipmapping. */
    221    t->validated = GL_FALSE;
    222 
    223    t->pp_txfilter &= ~(R200_MIN_FILTER_MASK | R200_MAG_FILTER_MASK);
    224    t->pp_txformat_x &= ~R200_VOLUME_FILTER_MASK;
    225 
    226    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
    227 	"%s(tex %p) minf %s, maxf %s, anisotropy %d.\n",
    228 	__func__, t,
    229 	_mesa_lookup_enum_by_nr(minf),
    230 	_mesa_lookup_enum_by_nr(magf),
    231 	anisotropy);
    232 
    233    if ( anisotropy == R200_MAX_ANISO_1_TO_1 ) {
    234       switch ( minf ) {
    235       case GL_NEAREST:
    236 	 t->pp_txfilter |= R200_MIN_FILTER_NEAREST;
    237 	 break;
    238       case GL_LINEAR:
    239 	 t->pp_txfilter |= R200_MIN_FILTER_LINEAR;
    240 	 break;
    241       case GL_NEAREST_MIPMAP_NEAREST:
    242 	 t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_NEAREST;
    243 	 break;
    244       case GL_NEAREST_MIPMAP_LINEAR:
    245 	 t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_NEAREST;
    246 	 break;
    247       case GL_LINEAR_MIPMAP_NEAREST:
    248 	 t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_LINEAR;
    249 	 break;
    250       case GL_LINEAR_MIPMAP_LINEAR:
    251 	 t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_LINEAR;
    252 	 break;
    253       }
    254    } else {
    255       switch ( minf ) {
    256       case GL_NEAREST:
    257 	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST;
    258 	 break;
    259       case GL_LINEAR:
    260 	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_LINEAR;
    261 	 break;
    262       case GL_NEAREST_MIPMAP_NEAREST:
    263       case GL_LINEAR_MIPMAP_NEAREST:
    264 	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
    265 	 break;
    266       case GL_NEAREST_MIPMAP_LINEAR:
    267       case GL_LINEAR_MIPMAP_LINEAR:
    268 	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
    269 	 break;
    270       }
    271    }
    272 
    273    /* Note we don't have 3D mipmaps so only use the mag filter setting
    274     * to set the 3D texture filter mode.
    275     */
    276    switch ( magf ) {
    277    case GL_NEAREST:
    278       t->pp_txfilter |= R200_MAG_FILTER_NEAREST;
    279       t->pp_txformat_x |= R200_VOLUME_FILTER_NEAREST;
    280       break;
    281    case GL_LINEAR:
    282       t->pp_txfilter |= R200_MAG_FILTER_LINEAR;
    283       t->pp_txformat_x |= R200_VOLUME_FILTER_LINEAR;
    284       break;
    285    }
    286 }
    287 
    288 static void r200SetTexBorderColor( radeonTexObjPtr t, const GLfloat color[4] )
    289 {
    290    GLubyte c[4];
    291    CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
    292    CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
    293    CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
    294    CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
    295    t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
    296 }
    297 
    298 static void r200TexEnv( struct gl_context *ctx, GLenum target,
    299 			  GLenum pname, const GLfloat *param )
    300 {
    301    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    302    GLuint unit = ctx->Texture.CurrentUnit;
    303    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
    304 
    305    radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_VERBOSE, "%s( %s )\n",
    306 	       __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
    307 
    308    /* This is incorrect: Need to maintain this data for each of
    309     * GL_TEXTURE_{123}D, GL_TEXTURE_RECTANGLE_NV, etc, and switch
    310     * between them according to _ReallyEnabled.
    311     */
    312    switch ( pname ) {
    313    case GL_TEXTURE_ENV_COLOR: {
    314       GLubyte c[4];
    315       GLuint envColor;
    316       _mesa_unclamped_float_rgba_to_ubyte(c, texUnit->EnvColor);
    317       envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
    318       if ( rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] != envColor ) {
    319 	 R200_STATECHANGE( rmesa, tf );
    320 	 rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] = envColor;
    321       }
    322       break;
    323    }
    324 
    325    case GL_TEXTURE_LOD_BIAS_EXT: {
    326       GLfloat bias, min;
    327       GLuint b;
    328       const int fixed_one = R200_LOD_BIAS_FIXED_ONE;
    329 
    330       /* The R200's LOD bias is a signed 2's complement value with a
    331        * range of -16.0 <= bias < 16.0.
    332        *
    333        * NOTE: Add a small bias to the bias for conform mipsel.c test.
    334        */
    335       bias = *param;
    336       min = driQueryOptionb (&rmesa->radeon.optionCache, "no_neg_lod_bias") ?
    337 	  0.0 : -16.0;
    338       bias = CLAMP( bias, min, 16.0 );
    339       b = ((int)(bias * fixed_one)
    340 		+ R200_LOD_BIAS_CORRECTION) & R200_LOD_BIAS_MASK;
    341 
    342       if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] & R200_LOD_BIAS_MASK) != b ) {
    343 	 R200_STATECHANGE( rmesa, tex[unit] );
    344 	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] &= ~R200_LOD_BIAS_MASK;
    345 	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] |= b;
    346       }
    347       break;
    348    }
    349    case GL_COORD_REPLACE_ARB:
    350       if (ctx->Point.PointSprite) {
    351 	 R200_STATECHANGE( rmesa, spr );
    352 	 if ((GLenum)param[0]) {
    353 	    rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] |= R200_PS_GEN_TEX_0 << unit;
    354 	 } else {
    355 	    rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] &= ~(R200_PS_GEN_TEX_0 << unit);
    356 	 }
    357       }
    358       break;
    359    default:
    360       return;
    361    }
    362 }
    363 
    364 void r200TexUpdateParameters(struct gl_context *ctx, GLuint unit)
    365 {
    366    struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
    367    radeonTexObj* t = radeon_tex_obj(ctx->Texture.Unit[unit]._Current);
    368 
    369    r200SetTexMaxAnisotropy(t , samp->MaxAnisotropy);
    370    r200SetTexFilter(t, samp->MinFilter, samp->MagFilter);
    371    r200SetTexWrap(t, samp->WrapS, samp->WrapT, samp->WrapR);
    372    r200SetTexBorderColor(t, samp->BorderColor.f);
    373 }
    374 
    375 /**
    376  * Changes variables and flags for a state update, which will happen at the
    377  * next UpdateTextureState
    378  */
    379 static void r200TexParameter( struct gl_context *ctx, GLenum target,
    380 				struct gl_texture_object *texObj,
    381 				GLenum pname, const GLfloat *params )
    382 {
    383    radeonTexObj* t = radeon_tex_obj(texObj);
    384 
    385    radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_VERBOSE,
    386 		"%s(%p, tex %p)  target %s, pname %s\n",
    387 		__FUNCTION__, ctx, texObj,
    388 		_mesa_lookup_enum_by_nr( target ),
    389 	       _mesa_lookup_enum_by_nr( pname ) );
    390 
    391    switch ( pname ) {
    392    case GL_TEXTURE_MIN_FILTER:
    393    case GL_TEXTURE_MAG_FILTER:
    394    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
    395    case GL_TEXTURE_WRAP_S:
    396    case GL_TEXTURE_WRAP_T:
    397    case GL_TEXTURE_WRAP_R:
    398    case GL_TEXTURE_BORDER_COLOR:
    399    case GL_TEXTURE_BASE_LEVEL:
    400    case GL_TEXTURE_MAX_LEVEL:
    401    case GL_TEXTURE_MIN_LOD:
    402    case GL_TEXTURE_MAX_LOD:
    403       t->validated = GL_FALSE;
    404       break;
    405 
    406    default:
    407       return;
    408    }
    409 }
    410 
    411 
    412 static void r200DeleteTexture(struct gl_context * ctx, struct gl_texture_object *texObj)
    413 {
    414    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    415    radeonTexObj* t = radeon_tex_obj(texObj);
    416 
    417    radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_NORMAL,
    418            "%s( %p (target = %s) )\n", __FUNCTION__,
    419 	   (void *)texObj,
    420 	   _mesa_lookup_enum_by_nr(texObj->Target));
    421 
    422    if (rmesa) {
    423       int i;
    424       radeon_firevertices(&rmesa->radeon);
    425       for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
    426 	 if ( t == rmesa->state.texture.unit[i].texobj ) {
    427 	    rmesa->state.texture.unit[i].texobj = NULL;
    428 	    rmesa->hw.tex[i].dirty = GL_FALSE;
    429 	    rmesa->hw.cube[i].dirty = GL_FALSE;
    430 	 }
    431       }
    432    }
    433 
    434    radeon_miptree_unreference(&t->mt);
    435 
    436    _mesa_delete_texture_object(ctx, texObj);
    437 }
    438 
    439 /* Need:
    440  *  - Same GEN_MODE for all active bits
    441  *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
    442  *  - STRQ presumably all supported (matrix means incoming R values
    443  *    can end up in STQ, this has implications for vertex support,
    444  *    presumably ok if maos is used, though?)
    445  *
    446  * Basically impossible to do this on the fly - just collect some
    447  * basic info & do the checks from ValidateState().
    448  */
    449 static void r200TexGen( struct gl_context *ctx,
    450 			  GLenum coord,
    451 			  GLenum pname,
    452 			  const GLfloat *params )
    453 {
    454    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    455    GLuint unit = ctx->Texture.CurrentUnit;
    456    rmesa->recheck_texgen[unit] = GL_TRUE;
    457 }
    458 
    459 
    460 /**
    461  * Allocate a new texture object.
    462  * Called via ctx->Driver.NewTextureObject.
    463  * Note: this function will be called during context creation to
    464  * allocate the default texture objects.
    465  * Fixup MaxAnisotropy according to user preference.
    466  */
    467 static struct gl_texture_object *r200NewTextureObject(struct gl_context * ctx,
    468 						      GLuint name,
    469 						      GLenum target)
    470 {
    471    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    472    radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
    473 
    474 
    475    radeon_print(RADEON_STATE | RADEON_TEXTURE, RADEON_NORMAL,
    476            "%s(%p) target %s, new texture %p.\n",
    477 	   __FUNCTION__, ctx,
    478 	   _mesa_lookup_enum_by_nr(target), t);
    479 
    480    _mesa_initialize_texture_object(&t->base, name, target);
    481    t->base.Sampler.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
    482 
    483    /* Initialize hardware state */
    484    r200SetTexWrap( t, t->base.Sampler.WrapS, t->base.Sampler.WrapT, t->base.Sampler.WrapR );
    485    r200SetTexMaxAnisotropy( t, t->base.Sampler.MaxAnisotropy );
    486    r200SetTexFilter(t, t->base.Sampler.MinFilter, t->base.Sampler.MagFilter);
    487    r200SetTexBorderColor(t, t->base.Sampler.BorderColor.f);
    488 
    489    return &t->base;
    490 }
    491 
    492 static struct gl_sampler_object *
    493 r200NewSamplerObject(struct gl_context *ctx, GLuint name)
    494 {
    495    r200ContextPtr rmesa = R200_CONTEXT(ctx);
    496    struct gl_sampler_object *samp = _mesa_new_sampler_object(ctx, name);
    497    if (samp)
    498       samp->MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
    499    return samp;
    500 }
    501 
    502 
    503 
    504 void r200InitTextureFuncs( radeonContextPtr radeon, struct dd_function_table *functions )
    505 {
    506    /* Note: we only plug in the functions we implement in the driver
    507     * since _mesa_init_driver_functions() was already called.
    508     */
    509 
    510    radeon_init_common_texture_funcs(radeon, functions);
    511 
    512    functions->NewTextureObject		= r200NewTextureObject;
    513    //   functions->BindTexture		= r200BindTexture;
    514    functions->DeleteTexture		= r200DeleteTexture;
    515 
    516    functions->TexEnv			= r200TexEnv;
    517    functions->TexParameter		= r200TexParameter;
    518    functions->TexGen			= r200TexGen;
    519    functions->NewSamplerObject		= r200NewSamplerObject;
    520 }
    521