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