r200_tex.c revision afe84fa698eae3e035e967589f0a8d55f6a83698
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/texstore.h"
42#include "main/teximage.h"
43#include "main/texobj.h"
44
45#include "radeon_mipmap_tree.h"
46#include "r200_context.h"
47#include "r200_state.h"
48#include "r200_ioctl.h"
49#include "r200_swtcl.h"
50#include "r200_tex.h"
51
52#include "xmlpool.h"
53
54
55
56/**
57 * Set the texture wrap modes.
58 *
59 * \param t Texture object whose wrap modes are to be set
60 * \param swrap Wrap mode for the \a s texture coordinate
61 * \param twrap Wrap mode for the \a t texture coordinate
62 */
63
64static void r200SetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap, GLenum rwrap )
65{
66   GLboolean  is_clamp = GL_FALSE;
67   GLboolean  is_clamp_to_border = GL_FALSE;
68   struct gl_texture_object *tObj = &t->base;
69
70   t->pp_txfilter &= ~(R200_CLAMP_S_MASK | R200_CLAMP_T_MASK | R200_BORDER_MODE_D3D);
71
72   switch ( swrap ) {
73   case GL_REPEAT:
74      t->pp_txfilter |= R200_CLAMP_S_WRAP;
75      break;
76   case GL_CLAMP:
77      t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
78      is_clamp = GL_TRUE;
79      break;
80   case GL_CLAMP_TO_EDGE:
81      t->pp_txfilter |= R200_CLAMP_S_CLAMP_LAST;
82      break;
83   case GL_CLAMP_TO_BORDER:
84      t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
85      is_clamp_to_border = GL_TRUE;
86      break;
87   case GL_MIRRORED_REPEAT:
88      t->pp_txfilter |= R200_CLAMP_S_MIRROR;
89      break;
90   case GL_MIRROR_CLAMP_EXT:
91      t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
92      is_clamp = GL_TRUE;
93      break;
94   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
95      t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_LAST;
96      break;
97   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
98      t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
99      is_clamp_to_border = GL_TRUE;
100      break;
101   default:
102      _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
103   }
104
105   if (tObj->Target != GL_TEXTURE_1D) {
106      switch ( twrap ) {
107      case GL_REPEAT:
108         t->pp_txfilter |= R200_CLAMP_T_WRAP;
109         break;
110      case GL_CLAMP:
111         t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
112         is_clamp = GL_TRUE;
113         break;
114      case GL_CLAMP_TO_EDGE:
115         t->pp_txfilter |= R200_CLAMP_T_CLAMP_LAST;
116         break;
117      case GL_CLAMP_TO_BORDER:
118         t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
119         is_clamp_to_border = GL_TRUE;
120         break;
121      case GL_MIRRORED_REPEAT:
122         t->pp_txfilter |= R200_CLAMP_T_MIRROR;
123         break;
124      case GL_MIRROR_CLAMP_EXT:
125         t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
126         is_clamp = GL_TRUE;
127         break;
128      case GL_MIRROR_CLAMP_TO_EDGE_EXT:
129         t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_LAST;
130         break;
131      case GL_MIRROR_CLAMP_TO_BORDER_EXT:
132         t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
133         is_clamp_to_border = GL_TRUE;
134         break;
135      default:
136         _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
137      }
138   }
139
140   t->pp_txformat_x &= ~R200_CLAMP_Q_MASK;
141
142   switch ( rwrap ) {
143   case GL_REPEAT:
144      t->pp_txformat_x |= R200_CLAMP_Q_WRAP;
145      break;
146   case GL_CLAMP:
147      t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
148      is_clamp = GL_TRUE;
149      break;
150   case GL_CLAMP_TO_EDGE:
151      t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_LAST;
152      break;
153   case GL_CLAMP_TO_BORDER:
154      t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
155      is_clamp_to_border = GL_TRUE;
156      break;
157   case GL_MIRRORED_REPEAT:
158      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR;
159      break;
160   case GL_MIRROR_CLAMP_EXT:
161      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
162      is_clamp = GL_TRUE;
163      break;
164   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
165      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_LAST;
166      break;
167   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
168      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
169      is_clamp_to_border = GL_TRUE;
170      break;
171   default:
172      _mesa_problem(NULL, "bad R wrap mode in %s", __FUNCTION__);
173   }
174
175   if ( is_clamp_to_border ) {
176      t->pp_txfilter |= R200_BORDER_MODE_D3D;
177   }
178
179   t->border_fallback = (is_clamp && is_clamp_to_border);
180}
181
182static void r200SetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
183{
184   t->pp_txfilter &= ~R200_MAX_ANISO_MASK;
185
186   if ( max <= 1.0 ) {
187      t->pp_txfilter |= R200_MAX_ANISO_1_TO_1;
188   } else if ( max <= 2.0 ) {
189      t->pp_txfilter |= R200_MAX_ANISO_2_TO_1;
190   } else if ( max <= 4.0 ) {
191      t->pp_txfilter |= R200_MAX_ANISO_4_TO_1;
192   } else if ( max <= 8.0 ) {
193      t->pp_txfilter |= R200_MAX_ANISO_8_TO_1;
194   } else {
195      t->pp_txfilter |= R200_MAX_ANISO_16_TO_1;
196   }
197}
198
199/**
200 * Set the texture magnification and minification modes.
201 *
202 * \param t Texture whose filter modes are to be set
203 * \param minf Texture minification mode
204 * \param magf Texture magnification mode
205 */
206
207static void r200SetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
208{
209   GLuint anisotropy = (t->pp_txfilter & R200_MAX_ANISO_MASK);
210
211   /* Force revalidation to account for switches from/to mipmapping. */
212   t->validated = GL_FALSE;
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, const GLfloat color[4] )
273{
274   GLubyte c[4];
275   CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
276   CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
277   CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
278   CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
279   t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
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 & RADEON_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 & (RADEON_STATE|RADEON_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->BorderColor );
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      t->validated = GL_FALSE;
389      break;
390
391   default:
392      return;
393   }
394}
395
396
397static void r200DeleteTexture(GLcontext * ctx, struct gl_texture_object *texObj)
398{
399   r200ContextPtr rmesa = R200_CONTEXT(ctx);
400   radeonTexObj* t = radeon_tex_obj(texObj);
401
402   if (RADEON_DEBUG & (RADEON_STATE | RADEON_TEXTURE)) {
403      fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__,
404	      (void *)texObj,
405	      _mesa_lookup_enum_by_nr(texObj->Target));
406   }
407
408   if (rmesa) {
409      int i;
410      radeon_firevertices(&rmesa->radeon);
411      for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
412	 if ( t == rmesa->state.texture.unit[i].texobj ) {
413	    rmesa->state.texture.unit[i].texobj = NULL;
414	    rmesa->hw.tex[i].dirty = GL_FALSE;
415	    rmesa->hw.cube[i].dirty = GL_FALSE;
416	 }
417      }
418   }
419
420   radeon_miptree_unreference(&t->mt);
421
422   _mesa_delete_texture_object(ctx, texObj);
423}
424
425/* Need:
426 *  - Same GEN_MODE for all active bits
427 *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
428 *  - STRQ presumably all supported (matrix means incoming R values
429 *    can end up in STQ, this has implications for vertex support,
430 *    presumably ok if maos is used, though?)
431 *
432 * Basically impossible to do this on the fly - just collect some
433 * basic info & do the checks from ValidateState().
434 */
435static void r200TexGen( GLcontext *ctx,
436			  GLenum coord,
437			  GLenum pname,
438			  const GLfloat *params )
439{
440   r200ContextPtr rmesa = R200_CONTEXT(ctx);
441   GLuint unit = ctx->Texture.CurrentUnit;
442   rmesa->recheck_texgen[unit] = GL_TRUE;
443}
444
445
446/**
447 * Allocate a new texture object.
448 * Called via ctx->Driver.NewTextureObject.
449 * Note: this function will be called during context creation to
450 * allocate the default texture objects.
451 * Fixup MaxAnisotropy according to user preference.
452 */
453static struct gl_texture_object *r200NewTextureObject(GLcontext * ctx,
454						      GLuint name,
455						      GLenum target)
456{
457   r200ContextPtr rmesa = R200_CONTEXT(ctx);
458   radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
459
460
461   if (RADEON_DEBUG & (RADEON_STATE | RADEON_TEXTURE)) {
462     fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__,
463	     t, _mesa_lookup_enum_by_nr(target));
464   }
465
466   _mesa_initialize_texture_object(&t->base, name, target);
467   t->base.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
468
469   /* Initialize hardware state */
470   r200SetTexWrap( t, t->base.WrapS, t->base.WrapT, t->base.WrapR );
471   r200SetTexMaxAnisotropy( t, t->base.MaxAnisotropy );
472   r200SetTexFilter(t, t->base.MinFilter, t->base.MagFilter);
473   r200SetTexBorderColor(t, t->base.BorderColor);
474
475   return &t->base;
476}
477
478
479
480void r200InitTextureFuncs( struct dd_function_table *functions )
481{
482   /* Note: we only plug in the functions we implement in the driver
483    * since _mesa_init_driver_functions() was already called.
484    */
485   functions->ChooseTextureFormat	= radeonChooseTextureFormat_mesa;
486   functions->TexImage1D		= radeonTexImage1D;
487   functions->TexImage2D		= radeonTexImage2D;
488#if ENABLE_HW_3D_TEXTURE
489   functions->TexImage3D		= radeonTexImage3D;
490#else
491   functions->TexImage3D		= _mesa_store_teximage3d;
492#endif
493   functions->TexSubImage1D		= radeonTexSubImage1D;
494   functions->TexSubImage2D		= radeonTexSubImage2D;
495#if ENABLE_HW_3D_TEXTURE
496   functions->TexSubImage3D		= radeonTexSubImage3D;
497#else
498   functions->TexSubImage3D		= _mesa_store_texsubimage3d;
499#endif
500   functions->GetTexImage               = radeonGetTexImage;
501   functions->GetCompressedTexImage     = radeonGetCompressedTexImage;
502   functions->NewTextureObject		= r200NewTextureObject;
503   //   functions->BindTexture		= r200BindTexture;
504   functions->DeleteTexture		= r200DeleteTexture;
505   functions->IsTextureResident		= driIsTextureResident;
506
507   functions->TexEnv			= r200TexEnv;
508   functions->TexParameter		= r200TexParameter;
509   functions->TexGen			= r200TexGen;
510
511   functions->CompressedTexImage2D	= radeonCompressedTexImage2D;
512   functions->CompressedTexSubImage2D	= radeonCompressedTexSubImage2D;
513
514   functions->GenerateMipmap = radeonGenerateMipmap;
515
516   functions->NewTextureImage = radeonNewTextureImage;
517   functions->FreeTexImageData = radeonFreeTexImageData;
518   functions->MapTexture = radeonMapTexture;
519   functions->UnmapTexture = radeonUnmapTexture;
520
521   driInitTextureFormats();
522
523}
524