radeon_tex.c revision 499f0685e8236eca410fce516de0e9bab7e25be8
1/*
2Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
3                     VA Linux Systems Inc., Fremont, California.
4
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice (including the
16next paragraph) shall be included in all copies or substantial
17portions of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26*/
27
28/*
29 * Authors:
30 *    Gareth Hughes <gareth@valinux.com>
31 *    Brian Paul <brianp@valinux.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_context.h"
47#include "radeon_mipmap_tree.h"
48#include "radeon_ioctl.h"
49#include "radeon_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 radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap )
64{
65   GLboolean  is_clamp = GL_FALSE;
66   GLboolean  is_clamp_to_border = GL_FALSE;
67
68   t->pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK | RADEON_BORDER_MODE_D3D);
69
70   switch ( swrap ) {
71   case GL_REPEAT:
72      t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
73      break;
74   case GL_CLAMP:
75      t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
76      is_clamp = GL_TRUE;
77      break;
78   case GL_CLAMP_TO_EDGE:
79      t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
80      break;
81   case GL_CLAMP_TO_BORDER:
82      t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
83      is_clamp_to_border = GL_TRUE;
84      break;
85   case GL_MIRRORED_REPEAT:
86      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR;
87      break;
88   case GL_MIRROR_CLAMP_EXT:
89      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
90      is_clamp = GL_TRUE;
91      break;
92   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
93      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_LAST;
94      break;
95   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
96      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
97      is_clamp_to_border = GL_TRUE;
98      break;
99   default:
100      _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
101   }
102
103   switch ( twrap ) {
104   case GL_REPEAT:
105      t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
106      break;
107   case GL_CLAMP:
108      t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
109      is_clamp = GL_TRUE;
110      break;
111   case GL_CLAMP_TO_EDGE:
112      t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
113      break;
114   case GL_CLAMP_TO_BORDER:
115      t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
116      is_clamp_to_border = GL_TRUE;
117      break;
118   case GL_MIRRORED_REPEAT:
119      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR;
120      break;
121   case GL_MIRROR_CLAMP_EXT:
122      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
123      is_clamp = GL_TRUE;
124      break;
125   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
126      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_LAST;
127      break;
128   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
129      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
130      is_clamp_to_border = GL_TRUE;
131      break;
132   default:
133      _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
134   }
135
136   if ( is_clamp_to_border ) {
137      t->pp_txfilter |= RADEON_BORDER_MODE_D3D;
138   }
139
140   t->border_fallback = (is_clamp && is_clamp_to_border);
141}
142
143static void radeonSetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
144{
145   t->pp_txfilter &= ~RADEON_MAX_ANISO_MASK;
146
147   if ( max == 1.0 ) {
148      t->pp_txfilter |= RADEON_MAX_ANISO_1_TO_1;
149   } else if ( max <= 2.0 ) {
150      t->pp_txfilter |= RADEON_MAX_ANISO_2_TO_1;
151   } else if ( max <= 4.0 ) {
152      t->pp_txfilter |= RADEON_MAX_ANISO_4_TO_1;
153   } else if ( max <= 8.0 ) {
154      t->pp_txfilter |= RADEON_MAX_ANISO_8_TO_1;
155   } else {
156      t->pp_txfilter |= RADEON_MAX_ANISO_16_TO_1;
157   }
158}
159
160/**
161 * Set the texture magnification and minification modes.
162 *
163 * \param t Texture whose filter modes are to be set
164 * \param minf Texture minification mode
165 * \param magf Texture magnification mode
166 */
167
168static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
169{
170   GLuint anisotropy = (t->pp_txfilter & RADEON_MAX_ANISO_MASK);
171
172   /* Force revalidation to account for switches from/to mipmapping. */
173   t->validated = GL_FALSE;
174
175   t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK);
176
177   /* r100 chips can't handle mipmaps/aniso for cubemap/volume textures */
178   if ( t->base.Target == GL_TEXTURE_CUBE_MAP ) {
179      switch ( minf ) {
180      case GL_NEAREST:
181      case GL_NEAREST_MIPMAP_NEAREST:
182      case GL_NEAREST_MIPMAP_LINEAR:
183	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
184	 break;
185      case GL_LINEAR:
186      case GL_LINEAR_MIPMAP_NEAREST:
187      case GL_LINEAR_MIPMAP_LINEAR:
188	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
189	 break;
190      default:
191	 break;
192      }
193   }
194   else if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
195      switch ( minf ) {
196      case GL_NEAREST:
197	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
198	 break;
199      case GL_LINEAR:
200	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
201	 break;
202      case GL_NEAREST_MIPMAP_NEAREST:
203	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
204	 break;
205      case GL_NEAREST_MIPMAP_LINEAR:
206	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
207	 break;
208      case GL_LINEAR_MIPMAP_NEAREST:
209	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
210	 break;
211      case GL_LINEAR_MIPMAP_LINEAR:
212	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
213	 break;
214      }
215   } else {
216      switch ( minf ) {
217      case GL_NEAREST:
218	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST;
219	 break;
220      case GL_LINEAR:
221	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_LINEAR;
222	 break;
223      case GL_NEAREST_MIPMAP_NEAREST:
224      case GL_LINEAR_MIPMAP_NEAREST:
225	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
226	 break;
227      case GL_NEAREST_MIPMAP_LINEAR:
228      case GL_LINEAR_MIPMAP_LINEAR:
229	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
230	 break;
231      }
232   }
233
234   switch ( magf ) {
235   case GL_NEAREST:
236      t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
237      break;
238   case GL_LINEAR:
239      t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
240      break;
241   }
242}
243
244static void radeonSetTexBorderColor( radeonTexObjPtr t, const GLfloat color[4] )
245{
246   GLubyte c[4];
247   CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
248   CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
249   CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
250   CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
251   t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
252}
253
254#define SCALED_FLOAT_TO_BYTE( x, scale ) \
255		(((GLuint)((255.0F / scale) * (x))) / 2)
256
257static void radeonTexEnv( struct gl_context *ctx, GLenum target,
258			  GLenum pname, const GLfloat *param )
259{
260   r100ContextPtr rmesa = R100_CONTEXT(ctx);
261   GLuint unit = ctx->Texture.CurrentUnit;
262   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
263
264   if ( RADEON_DEBUG & RADEON_STATE ) {
265      fprintf( stderr, "%s( %s )\n",
266	       __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
267   }
268
269   switch ( pname ) {
270   case GL_TEXTURE_ENV_COLOR: {
271      GLubyte c[4];
272      GLuint envColor;
273      _mesa_unclamped_float_rgba_to_ubyte(c, texUnit->EnvColor);
274      envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
275      if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
276	 RADEON_STATECHANGE( rmesa, tex[unit] );
277	 rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
278      }
279      break;
280   }
281
282   case GL_TEXTURE_LOD_BIAS_EXT: {
283      GLfloat bias, min;
284      GLuint b;
285
286      /* The Radeon's LOD bias is a signed 2's complement value with a
287       * range of -1.0 <= bias < 4.0.  We break this into two linear
288       * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping
289       * [0.0,4.0] to [0,127].
290       */
291      min = driQueryOptionb (&rmesa->radeon.optionCache, "no_neg_lod_bias") ?
292	  0.0 : -1.0;
293      bias = CLAMP( *param, min, 4.0 );
294      if ( bias == 0 ) {
295	 b = 0;
296      } else if ( bias > 0 ) {
297	 b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 4.0 )) << RADEON_LOD_BIAS_SHIFT;
298      } else {
299	 b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 1.0 )) << RADEON_LOD_BIAS_SHIFT;
300      }
301      if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] & RADEON_LOD_BIAS_MASK) != b ) {
302	 RADEON_STATECHANGE( rmesa, tex[unit] );
303	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] &= ~RADEON_LOD_BIAS_MASK;
304	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] |= (b & RADEON_LOD_BIAS_MASK);
305      }
306      break;
307   }
308
309   default:
310      return;
311   }
312}
313
314
315/**
316 * Changes variables and flags for a state update, which will happen at the
317 * next UpdateTextureState
318 */
319
320static void radeonTexParameter( struct gl_context *ctx, GLenum target,
321				struct gl_texture_object *texObj,
322				GLenum pname, const GLfloat *params )
323{
324   radeonTexObj* t = radeon_tex_obj(texObj);
325
326   radeon_print(RADEON_TEXTURE, RADEON_VERBOSE, "%s( %s )\n", __FUNCTION__,
327	       _mesa_lookup_enum_by_nr( pname ) );
328
329   switch ( pname ) {
330   case GL_TEXTURE_MIN_FILTER:
331   case GL_TEXTURE_MAG_FILTER:
332   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
333      radeonSetTexMaxAnisotropy( t, texObj->Sampler.MaxAnisotropy );
334      radeonSetTexFilter( t, texObj->Sampler.MinFilter, texObj->Sampler.MagFilter );
335      break;
336
337   case GL_TEXTURE_WRAP_S:
338   case GL_TEXTURE_WRAP_T:
339      radeonSetTexWrap( t, texObj->Sampler.WrapS, texObj->Sampler.WrapT );
340      break;
341
342   case GL_TEXTURE_BORDER_COLOR:
343      radeonSetTexBorderColor( t, texObj->Sampler.BorderColor.f );
344      break;
345
346   case GL_TEXTURE_BASE_LEVEL:
347   case GL_TEXTURE_MAX_LEVEL:
348   case GL_TEXTURE_MIN_LOD:
349   case GL_TEXTURE_MAX_LOD:
350      t->validated = GL_FALSE;
351      break;
352
353   default:
354      return;
355   }
356}
357
358static void radeonDeleteTexture( struct gl_context *ctx,
359				 struct gl_texture_object *texObj )
360{
361   r100ContextPtr rmesa = R100_CONTEXT(ctx);
362   radeonTexObj* t = radeon_tex_obj(texObj);
363   int i;
364
365   radeon_print(RADEON_TEXTURE, RADEON_NORMAL,
366	 "%s( %p (target = %s) )\n", __FUNCTION__, (void *)texObj,
367	       _mesa_lookup_enum_by_nr( texObj->Target ) );
368
369   if ( rmesa ) {
370     radeon_firevertices(&rmesa->radeon);
371     for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
372       if ( t == rmesa->state.texture.unit[i].texobj ) {
373	 rmesa->state.texture.unit[i].texobj = NULL;
374	 rmesa->hw.tex[i].dirty = GL_FALSE;
375	 rmesa->hw.cube[i].dirty = GL_FALSE;
376       }
377     }
378   }
379
380   radeon_miptree_unreference(&t->mt);
381
382   /* Free mipmap images and the texture object itself */
383   _mesa_delete_texture_object(ctx, texObj);
384}
385
386/* Need:
387 *  - Same GEN_MODE for all active bits
388 *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
389 *  - STRQ presumably all supported (matrix means incoming R values
390 *    can end up in STQ, this has implications for vertex support,
391 *    presumably ok if maos is used, though?)
392 *
393 * Basically impossible to do this on the fly - just collect some
394 * basic info & do the checks from ValidateState().
395 */
396static void radeonTexGen( struct gl_context *ctx,
397			  GLenum coord,
398			  GLenum pname,
399			  const GLfloat *params )
400{
401   r100ContextPtr rmesa = R100_CONTEXT(ctx);
402   GLuint unit = ctx->Texture.CurrentUnit;
403   rmesa->recheck_texgen[unit] = GL_TRUE;
404}
405
406/**
407 * Allocate a new texture object.
408 * Called via ctx->Driver.NewTextureObject.
409 * Note: we could use containment here to 'derive' the driver-specific
410 * texture object from the core mesa gl_texture_object.  Not done at this time.
411 */
412static struct gl_texture_object *
413radeonNewTextureObject( struct gl_context *ctx, GLuint name, GLenum target )
414{
415   r100ContextPtr rmesa = R100_CONTEXT(ctx);
416   radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
417
418   _mesa_initialize_texture_object(&t->base, name, target);
419   t->base.Sampler.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
420
421   t->border_fallback = GL_FALSE;
422
423   t->pp_txfilter = RADEON_BORDER_MODE_OGL;
424   t->pp_txformat = (RADEON_TXFORMAT_ENDIAN_NO_SWAP |
425		     RADEON_TXFORMAT_PERSPECTIVE_ENABLE);
426
427   radeonSetTexWrap( t, t->base.Sampler.WrapS, t->base.Sampler.WrapT );
428   radeonSetTexMaxAnisotropy( t, t->base.Sampler.MaxAnisotropy );
429   radeonSetTexFilter( t, t->base.Sampler.MinFilter, t->base.Sampler.MagFilter );
430   radeonSetTexBorderColor( t, t->base.Sampler.BorderColor.f );
431   return &t->base;
432}
433
434
435
436void radeonInitTextureFuncs( radeonContextPtr radeon, struct dd_function_table *functions )
437{
438   radeon_init_common_texture_funcs(radeon, functions);
439
440   functions->NewTextureObject		= radeonNewTextureObject;
441   //   functions->BindTexture		= radeonBindTexture;
442   functions->DeleteTexture		= radeonDeleteTexture;
443
444   functions->TexEnv			= radeonTexEnv;
445   functions->TexParameter		= radeonTexParameter;
446   functions->TexGen			= radeonTexGen;
447}
448