r200_tex.c revision 0bb29949ba8a9e5a15dc0640dbb0a4e7990a1d57
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/mfeatures.h"
41#include "main/simple_list.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_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
63static 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
188static 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
216static 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
288static 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
298static 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      UNCLAMPED_FLOAT_TO_RGBA_CHAN( 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
365/**
366 * Changes variables and flags for a state update, which will happen at the
367 * next UpdateTextureState
368 */
369
370static void r200TexParameter( struct gl_context *ctx, GLenum target,
371				struct gl_texture_object *texObj,
372				GLenum pname, const GLfloat *params )
373{
374   radeonTexObj* t = radeon_tex_obj(texObj);
375
376   radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_VERBOSE,
377		"%s(%p, tex %p)  target %s, pname %s\n",
378		__FUNCTION__, ctx, texObj,
379		_mesa_lookup_enum_by_nr( target ),
380	       _mesa_lookup_enum_by_nr( pname ) );
381
382   switch ( pname ) {
383   case GL_TEXTURE_MIN_FILTER:
384   case GL_TEXTURE_MAG_FILTER:
385   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
386      r200SetTexMaxAnisotropy( t, texObj->Sampler.MaxAnisotropy );
387      r200SetTexFilter( t, texObj->Sampler.MinFilter, texObj->Sampler.MagFilter );
388      break;
389
390   case GL_TEXTURE_WRAP_S:
391   case GL_TEXTURE_WRAP_T:
392   case GL_TEXTURE_WRAP_R:
393      r200SetTexWrap( t, texObj->Sampler.WrapS, texObj->Sampler.WrapT, texObj->Sampler.WrapR );
394      break;
395
396   case GL_TEXTURE_BORDER_COLOR:
397      r200SetTexBorderColor( t, texObj->Sampler.BorderColor.f );
398      break;
399
400   case GL_TEXTURE_BASE_LEVEL:
401   case GL_TEXTURE_MAX_LEVEL:
402   case GL_TEXTURE_MIN_LOD:
403   case GL_TEXTURE_MAX_LOD:
404      t->validated = GL_FALSE;
405      break;
406
407   default:
408      return;
409   }
410}
411
412
413static void r200DeleteTexture(struct gl_context * ctx, struct gl_texture_object *texObj)
414{
415   r200ContextPtr rmesa = R200_CONTEXT(ctx);
416   radeonTexObj* t = radeon_tex_obj(texObj);
417
418   radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_NORMAL,
419           "%s( %p (target = %s) )\n", __FUNCTION__,
420	   (void *)texObj,
421	   _mesa_lookup_enum_by_nr(texObj->Target));
422
423   if (rmesa) {
424      int i;
425      radeon_firevertices(&rmesa->radeon);
426      for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
427	 if ( t == rmesa->state.texture.unit[i].texobj ) {
428	    rmesa->state.texture.unit[i].texobj = NULL;
429	    rmesa->hw.tex[i].dirty = GL_FALSE;
430	    rmesa->hw.cube[i].dirty = GL_FALSE;
431	 }
432      }
433   }
434
435   radeon_miptree_unreference(&t->mt);
436
437   _mesa_delete_texture_object(ctx, texObj);
438}
439
440/* Need:
441 *  - Same GEN_MODE for all active bits
442 *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
443 *  - STRQ presumably all supported (matrix means incoming R values
444 *    can end up in STQ, this has implications for vertex support,
445 *    presumably ok if maos is used, though?)
446 *
447 * Basically impossible to do this on the fly - just collect some
448 * basic info & do the checks from ValidateState().
449 */
450static void r200TexGen( struct gl_context *ctx,
451			  GLenum coord,
452			  GLenum pname,
453			  const GLfloat *params )
454{
455   r200ContextPtr rmesa = R200_CONTEXT(ctx);
456   GLuint unit = ctx->Texture.CurrentUnit;
457   rmesa->recheck_texgen[unit] = GL_TRUE;
458}
459
460
461/**
462 * Allocate a new texture object.
463 * Called via ctx->Driver.NewTextureObject.
464 * Note: this function will be called during context creation to
465 * allocate the default texture objects.
466 * Fixup MaxAnisotropy according to user preference.
467 */
468static struct gl_texture_object *r200NewTextureObject(struct gl_context * ctx,
469						      GLuint name,
470						      GLenum target)
471{
472   r200ContextPtr rmesa = R200_CONTEXT(ctx);
473   radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
474
475
476   radeon_print(RADEON_STATE | RADEON_TEXTURE, RADEON_NORMAL,
477           "%s(%p) target %s, new texture %p.\n",
478	   __FUNCTION__, ctx,
479	   _mesa_lookup_enum_by_nr(target), t);
480
481   _mesa_initialize_texture_object(&t->base, name, target);
482   t->base.Sampler.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
483
484   /* Initialize hardware state */
485   r200SetTexWrap( t, t->base.Sampler.WrapS, t->base.Sampler.WrapT, t->base.Sampler.WrapR );
486   r200SetTexMaxAnisotropy( t, t->base.Sampler.MaxAnisotropy );
487   r200SetTexFilter(t, t->base.Sampler.MinFilter, t->base.Sampler.MagFilter);
488   r200SetTexBorderColor(t, t->base.Sampler.BorderColor.f);
489
490   return &t->base;
491}
492
493
494
495void r200InitTextureFuncs( radeonContextPtr radeon, struct dd_function_table *functions )
496{
497   /* Note: we only plug in the functions we implement in the driver
498    * since _mesa_init_driver_functions() was already called.
499    */
500   functions->ChooseTextureFormat	= radeonChooseTextureFormat_mesa;
501   functions->TexImage1D		= radeonTexImage1D;
502   functions->TexImage2D		= radeonTexImage2D;
503#if ENABLE_HW_3D_TEXTURE
504   functions->TexImage3D		= radeonTexImage3D;
505#else
506   functions->TexImage3D		= _mesa_store_teximage3d;
507#endif
508   functions->TexSubImage1D		= radeonTexSubImage1D;
509   functions->TexSubImage2D		= radeonTexSubImage2D;
510#if ENABLE_HW_3D_TEXTURE
511   functions->TexSubImage3D		= radeonTexSubImage3D;
512#else
513   functions->TexSubImage3D		= _mesa_store_texsubimage3d;
514#endif
515   functions->GetTexImage               = radeonGetTexImage;
516   functions->GetCompressedTexImage     = radeonGetCompressedTexImage;
517   functions->NewTextureObject		= r200NewTextureObject;
518   //   functions->BindTexture		= r200BindTexture;
519   functions->DeleteTexture		= r200DeleteTexture;
520   functions->IsTextureResident		= driIsTextureResident;
521
522   functions->TexEnv			= r200TexEnv;
523   functions->TexParameter		= r200TexParameter;
524   functions->TexGen			= r200TexGen;
525
526   functions->CompressedTexImage2D	= radeonCompressedTexImage2D;
527   functions->CompressedTexSubImage2D	= radeonCompressedTexSubImage2D;
528
529   if (radeon->radeonScreen->kernel_mm) {
530      functions->CopyTexSubImage2D = radeonCopyTexSubImage2D;
531   }
532
533   functions->GenerateMipmap = radeonGenerateMipmap;
534
535   functions->NewTextureImage = radeonNewTextureImage;
536   functions->FreeTextureImageBuffer = radeonFreeTextureImageBuffer;
537   functions->MapTexture = radeonMapTexture;
538   functions->UnmapTexture = radeonUnmapTexture;
539
540#if FEATURE_OES_EGL_image
541   functions->EGLImageTargetTexture2D = radeon_image_target_texture_2d;
542#endif
543
544   driInitTextureFormats();
545
546}
547