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