r200_tex.c revision 8452814ec6f536fc4177e6c34ff5b8b6d3102a3a
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 "glheader.h"
35#include "imports.h"
36#include "colormac.h"
37#include "context.h"
38#include "enums.h"
39#include "image.h"
40#include "simple_list.h"
41#include "texformat.h"
42#include "texstore.h"
43#include "texmem.h"
44#include "teximage.h"
45#include "texobj.h"
46
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( r200TexObjPtr t, GLenum swrap, GLenum twrap, GLenum rwrap )
66{
67   GLboolean  is_clamp = GL_FALSE;
68   GLboolean  is_clamp_to_border = GL_FALSE;
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   switch ( twrap ) {
106   case GL_REPEAT:
107      t->pp_txfilter |= R200_CLAMP_T_WRAP;
108      break;
109   case GL_CLAMP:
110      t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
111      is_clamp = GL_TRUE;
112      break;
113   case GL_CLAMP_TO_EDGE:
114      t->pp_txfilter |= R200_CLAMP_T_CLAMP_LAST;
115      break;
116   case GL_CLAMP_TO_BORDER:
117      t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
118      is_clamp_to_border = GL_TRUE;
119      break;
120   case GL_MIRRORED_REPEAT:
121      t->pp_txfilter |= R200_CLAMP_T_MIRROR;
122      break;
123   case GL_MIRROR_CLAMP_EXT:
124      t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
125      is_clamp = GL_TRUE;
126      break;
127   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
128      t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_LAST;
129      break;
130   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
131      t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
132      is_clamp_to_border = GL_TRUE;
133      break;
134   default:
135      _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
136   }
137
138   t->pp_txformat_x &= ~R200_CLAMP_Q_MASK;
139
140   switch ( rwrap ) {
141   case GL_REPEAT:
142      t->pp_txformat_x |= R200_CLAMP_Q_WRAP;
143      break;
144   case GL_CLAMP:
145      t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
146      is_clamp = GL_TRUE;
147      break;
148   case GL_CLAMP_TO_EDGE:
149      t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_LAST;
150      break;
151   case GL_CLAMP_TO_BORDER:
152      t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
153      is_clamp_to_border = GL_TRUE;
154      break;
155   case GL_MIRRORED_REPEAT:
156      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR;
157      break;
158   case GL_MIRROR_CLAMP_EXT:
159      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
160      is_clamp = GL_TRUE;
161      break;
162   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
163      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_LAST;
164      break;
165   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
166      t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
167      is_clamp_to_border = GL_TRUE;
168      break;
169   default:
170      _mesa_problem(NULL, "bad R wrap mode in %s", __FUNCTION__);
171   }
172
173   if ( is_clamp_to_border ) {
174      t->pp_txfilter |= R200_BORDER_MODE_D3D;
175   }
176
177   t->border_fallback = (is_clamp && is_clamp_to_border);
178}
179
180static void r200SetTexMaxAnisotropy( r200TexObjPtr t, GLfloat max )
181{
182   t->pp_txfilter &= ~R200_MAX_ANISO_MASK;
183
184   if ( max <= 1.0 ) {
185      t->pp_txfilter |= R200_MAX_ANISO_1_TO_1;
186   } else if ( max <= 2.0 ) {
187      t->pp_txfilter |= R200_MAX_ANISO_2_TO_1;
188   } else if ( max <= 4.0 ) {
189      t->pp_txfilter |= R200_MAX_ANISO_4_TO_1;
190   } else if ( max <= 8.0 ) {
191      t->pp_txfilter |= R200_MAX_ANISO_8_TO_1;
192   } else {
193      t->pp_txfilter |= R200_MAX_ANISO_16_TO_1;
194   }
195}
196
197/**
198 * Set the texture magnification and minification modes.
199 *
200 * \param t Texture whose filter modes are to be set
201 * \param minf Texture minification mode
202 * \param magf Texture magnification mode
203 */
204
205static void r200SetTexFilter( r200TexObjPtr t, GLenum minf, GLenum magf )
206{
207   GLuint anisotropy = (t->pp_txfilter & R200_MAX_ANISO_MASK);
208
209   t->pp_txfilter &= ~(R200_MIN_FILTER_MASK | R200_MAG_FILTER_MASK);
210   t->pp_txformat_x &= ~R200_VOLUME_FILTER_MASK;
211
212   if ( anisotropy == R200_MAX_ANISO_1_TO_1 ) {
213      switch ( minf ) {
214      case GL_NEAREST:
215	 t->pp_txfilter |= R200_MIN_FILTER_NEAREST;
216	 break;
217      case GL_LINEAR:
218	 t->pp_txfilter |= R200_MIN_FILTER_LINEAR;
219	 break;
220      case GL_NEAREST_MIPMAP_NEAREST:
221	 t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_NEAREST;
222	 break;
223      case GL_NEAREST_MIPMAP_LINEAR:
224	 t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_NEAREST;
225	 break;
226      case GL_LINEAR_MIPMAP_NEAREST:
227	 t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_LINEAR;
228	 break;
229      case GL_LINEAR_MIPMAP_LINEAR:
230	 t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_LINEAR;
231	 break;
232      }
233   } else {
234      switch ( minf ) {
235      case GL_NEAREST:
236	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST;
237	 break;
238      case GL_LINEAR:
239	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_LINEAR;
240	 break;
241      case GL_NEAREST_MIPMAP_NEAREST:
242      case GL_LINEAR_MIPMAP_NEAREST:
243	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
244	 break;
245      case GL_NEAREST_MIPMAP_LINEAR:
246      case GL_LINEAR_MIPMAP_LINEAR:
247	 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
248	 break;
249      }
250   }
251
252   /* Note we don't have 3D mipmaps so only use the mag filter setting
253    * to set the 3D texture filter mode.
254    */
255   switch ( magf ) {
256   case GL_NEAREST:
257      t->pp_txfilter |= R200_MAG_FILTER_NEAREST;
258      t->pp_txformat_x |= R200_VOLUME_FILTER_NEAREST;
259      break;
260   case GL_LINEAR:
261      t->pp_txfilter |= R200_MAG_FILTER_LINEAR;
262      t->pp_txformat_x |= R200_VOLUME_FILTER_LINEAR;
263      break;
264   }
265}
266
267static void r200SetTexBorderColor( r200TexObjPtr t, GLubyte c[4] )
268{
269   t->pp_border_color = r200PackColor( 4, c[0], c[1], c[2], c[3] );
270}
271
272
273/**
274 * Allocate space for and load the mesa images into the texture memory block.
275 * This will happen before drawing with a new texture, or drawing with a
276 * texture after it was swapped out or teximaged again.
277 */
278
279static r200TexObjPtr r200AllocTexObj( struct gl_texture_object *texObj )
280{
281   r200TexObjPtr t;
282
283   t = CALLOC_STRUCT( r200_tex_obj );
284   texObj->DriverData = t;
285   if ( t != NULL ) {
286      if ( R200_DEBUG & DEBUG_TEXTURE ) {
287	 fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, (void *)texObj,
288		  (void *)t );
289      }
290
291      /* Initialize non-image-dependent parts of the state:
292       */
293      t->base.tObj = texObj;
294      t->border_fallback = GL_FALSE;
295
296      make_empty_list( & t->base );
297
298      r200SetTexWrap( t, texObj->WrapS, texObj->WrapT, texObj->WrapR );
299      r200SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
300      r200SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
301      r200SetTexBorderColor( t, texObj->_BorderChan );
302   }
303
304   return t;
305}
306
307/* try to find a format which will only need a memcopy */
308static const struct gl_texture_format *
309r200Choose8888TexFormat( GLenum srcFormat, GLenum srcType )
310{
311   const GLuint ui = 1;
312   const GLubyte littleEndian = *((const GLubyte *) &ui);
313
314   if ((srcFormat == GL_RGBA && srcType == GL_UNSIGNED_INT_8_8_8_8) ||
315       (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE && !littleEndian) ||
316       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_INT_8_8_8_8_REV) ||
317       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_BYTE && littleEndian)) {
318      return &_mesa_texformat_rgba8888;
319   }
320   else if ((srcFormat == GL_RGBA && srcType == GL_UNSIGNED_INT_8_8_8_8_REV) ||
321       (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE && littleEndian) ||
322       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_INT_8_8_8_8) ||
323       (srcFormat == GL_ABGR_EXT && srcType == GL_UNSIGNED_BYTE && !littleEndian)) {
324      return &_mesa_texformat_rgba8888_rev;
325   }
326   else return _dri_texformat_argb8888;
327}
328
329static const struct gl_texture_format *
330r200ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
331                           GLenum format, GLenum type )
332{
333   r200ContextPtr rmesa = R200_CONTEXT(ctx);
334   const GLboolean do32bpt =
335       ( rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
336   const GLboolean force16bpt =
337       ( rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
338   (void) format;
339
340   switch ( internalFormat ) {
341   case 4:
342   case GL_RGBA:
343   case GL_COMPRESSED_RGBA:
344      switch ( type ) {
345      case GL_UNSIGNED_INT_10_10_10_2:
346      case GL_UNSIGNED_INT_2_10_10_10_REV:
347	 return do32bpt ? _dri_texformat_argb8888 : _dri_texformat_argb1555;
348      case GL_UNSIGNED_SHORT_4_4_4_4:
349      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
350	 return _dri_texformat_argb4444;
351      case GL_UNSIGNED_SHORT_5_5_5_1:
352      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
353	 return _dri_texformat_argb1555;
354      default:
355         return do32bpt ?
356	    r200Choose8888TexFormat(format, type) : _dri_texformat_argb4444;
357      }
358
359   case 3:
360   case GL_RGB:
361   case GL_COMPRESSED_RGB:
362      switch ( type ) {
363      case GL_UNSIGNED_SHORT_4_4_4_4:
364      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
365	 return _dri_texformat_argb4444;
366      case GL_UNSIGNED_SHORT_5_5_5_1:
367      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
368	 return _dri_texformat_argb1555;
369      case GL_UNSIGNED_SHORT_5_6_5:
370      case GL_UNSIGNED_SHORT_5_6_5_REV:
371	 return _dri_texformat_rgb565;
372      default:
373         return do32bpt ? _dri_texformat_argb8888 : _dri_texformat_rgb565;
374      }
375
376   case GL_RGBA8:
377   case GL_RGB10_A2:
378   case GL_RGBA12:
379   case GL_RGBA16:
380      return !force16bpt ?
381	  r200Choose8888TexFormat(format, type) : _dri_texformat_argb4444;
382
383   case GL_RGBA4:
384   case GL_RGBA2:
385      return _dri_texformat_argb4444;
386
387   case GL_RGB5_A1:
388      return _dri_texformat_argb1555;
389
390   case GL_RGB8:
391   case GL_RGB10:
392   case GL_RGB12:
393   case GL_RGB16:
394      return !force16bpt ? _dri_texformat_argb8888 : _dri_texformat_rgb565;
395
396   case GL_RGB5:
397   case GL_RGB4:
398   case GL_R3_G3_B2:
399      return _dri_texformat_rgb565;
400
401   case GL_ALPHA:
402   case GL_ALPHA4:
403   case GL_ALPHA8:
404   case GL_ALPHA12:
405   case GL_ALPHA16:
406   case GL_COMPRESSED_ALPHA:
407   /* can't use a8 format since interpreting hw I8 as a8 would result
408      in wrong rgb values (same as alpha value instead of 0). */
409      return _dri_texformat_al88;
410
411   case 1:
412   case GL_LUMINANCE:
413   case GL_LUMINANCE4:
414   case GL_LUMINANCE8:
415   case GL_LUMINANCE12:
416   case GL_LUMINANCE16:
417   case GL_COMPRESSED_LUMINANCE:
418      return _dri_texformat_l8;
419
420   case 2:
421   case GL_LUMINANCE_ALPHA:
422   case GL_LUMINANCE4_ALPHA4:
423   case GL_LUMINANCE6_ALPHA2:
424   case GL_LUMINANCE8_ALPHA8:
425   case GL_LUMINANCE12_ALPHA4:
426   case GL_LUMINANCE12_ALPHA12:
427   case GL_LUMINANCE16_ALPHA16:
428   case GL_COMPRESSED_LUMINANCE_ALPHA:
429      return _dri_texformat_al88;
430
431   case GL_INTENSITY:
432   case GL_INTENSITY4:
433   case GL_INTENSITY8:
434   case GL_INTENSITY12:
435   case GL_INTENSITY16:
436   case GL_COMPRESSED_INTENSITY:
437       return _dri_texformat_i8;
438
439   case GL_YCBCR_MESA:
440      if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
441          type == GL_UNSIGNED_BYTE)
442         return &_mesa_texformat_ycbcr;
443      else
444         return &_mesa_texformat_ycbcr_rev;
445
446   case GL_RGB_S3TC:
447   case GL_RGB4_S3TC:
448   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
449      return &_mesa_texformat_rgb_dxt1;
450
451   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
452      return &_mesa_texformat_rgba_dxt1;
453
454   case GL_RGBA_S3TC:
455   case GL_RGBA4_S3TC:
456   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
457      return &_mesa_texformat_rgba_dxt3;
458
459   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
460      return &_mesa_texformat_rgba_dxt5;
461
462   default:
463      _mesa_problem(ctx,
464         "unexpected internalFormat 0x%x in r200ChooseTextureFormat",
465         (int) internalFormat);
466      return NULL;
467   }
468
469   return NULL; /* never get here */
470}
471
472
473static GLboolean
474r200ValidateClientStorage( GLcontext *ctx, GLenum target,
475			   GLint internalFormat,
476			   GLint srcWidth, GLint srcHeight,
477                           GLenum format, GLenum type,  const void *pixels,
478			   const struct gl_pixelstore_attrib *packing,
479			   struct gl_texture_object *texObj,
480			   struct gl_texture_image *texImage)
481
482{
483   r200ContextPtr rmesa = R200_CONTEXT(ctx);
484
485   if ( R200_DEBUG & DEBUG_TEXTURE )
486      fprintf(stderr, "intformat %s format %s type %s\n",
487	      _mesa_lookup_enum_by_nr( internalFormat ),
488	      _mesa_lookup_enum_by_nr( format ),
489	      _mesa_lookup_enum_by_nr( type ));
490
491   if (!ctx->Unpack.ClientStorage)
492      return 0;
493
494   if (ctx->_ImageTransferState ||
495       texImage->IsCompressed ||
496       texObj->GenerateMipmap)
497      return 0;
498
499
500   /* This list is incomplete, may be different on ppc???
501    */
502   switch ( internalFormat ) {
503   case GL_RGBA:
504      if ( format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
505	 texImage->TexFormat = _dri_texformat_argb8888;
506      }
507      else
508	 return 0;
509      break;
510
511   case GL_RGB:
512      if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
513	 texImage->TexFormat = _dri_texformat_rgb565;
514      }
515      else
516	 return 0;
517      break;
518
519   case GL_YCBCR_MESA:
520      if ( format == GL_YCBCR_MESA &&
521	   type == GL_UNSIGNED_SHORT_8_8_REV_APPLE ) {
522	 texImage->TexFormat = &_mesa_texformat_ycbcr_rev;
523      }
524      else if ( format == GL_YCBCR_MESA &&
525		(type == GL_UNSIGNED_SHORT_8_8_APPLE ||
526		 type == GL_UNSIGNED_BYTE)) {
527	 texImage->TexFormat = &_mesa_texformat_ycbcr;
528      }
529      else
530	 return 0;
531      break;
532
533   default:
534      return 0;
535   }
536
537   /* Could deal with these packing issues, but currently don't:
538    */
539   if (packing->SkipPixels ||
540       packing->SkipRows ||
541       packing->SwapBytes ||
542       packing->LsbFirst) {
543      return 0;
544   }
545
546   {
547      GLint srcRowStride = _mesa_image_row_stride(packing, srcWidth,
548						  format, type);
549
550
551      if ( R200_DEBUG & DEBUG_TEXTURE )
552	 fprintf(stderr, "%s: srcRowStride %d/%x\n",
553		 __FUNCTION__, srcRowStride, srcRowStride);
554
555      /* Could check this later in upload, pitch restrictions could be
556       * relaxed, but would need to store the image pitch somewhere,
557       * as packing details might change before image is uploaded:
558       */
559      if (!r200IsGartMemory( rmesa, pixels, srcHeight * srcRowStride ) ||
560	  (srcRowStride & 63))
561	 return 0;
562
563
564      /* Have validated that _mesa_transfer_teximage would be a straight
565       * memcpy at this point.  NOTE: future calls to TexSubImage will
566       * overwrite the client data.  This is explicitly mentioned in the
567       * extension spec.
568       */
569      texImage->Data = (void *)pixels;
570      texImage->IsClientData = GL_TRUE;
571      texImage->RowStride = srcRowStride / texImage->TexFormat->TexelBytes;
572
573      return 1;
574   }
575}
576
577
578static void r200TexImage1D( GLcontext *ctx, GLenum target, GLint level,
579                              GLint internalFormat,
580                              GLint width, GLint border,
581                              GLenum format, GLenum type, const GLvoid *pixels,
582                              const struct gl_pixelstore_attrib *packing,
583                              struct gl_texture_object *texObj,
584                              struct gl_texture_image *texImage )
585{
586   driTextureObject * t = (driTextureObject *) texObj->DriverData;
587
588   if ( t ) {
589      driSwapOutTextureObject( t );
590   }
591   else {
592      t = (driTextureObject *) r200AllocTexObj( texObj );
593      if (!t) {
594         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
595         return;
596      }
597   }
598
599   /* Note, this will call ChooseTextureFormat */
600   _mesa_store_teximage1d(ctx, target, level, internalFormat,
601                          width, border, format, type, pixels,
602                          &ctx->Unpack, texObj, texImage);
603
604   t->dirty_images[0] |= (1 << level);
605}
606
607
608static void r200TexSubImage1D( GLcontext *ctx, GLenum target, GLint level,
609                                 GLint xoffset,
610                                 GLsizei width,
611                                 GLenum format, GLenum type,
612                                 const GLvoid *pixels,
613                                 const struct gl_pixelstore_attrib *packing,
614                                 struct gl_texture_object *texObj,
615                                 struct gl_texture_image *texImage )
616{
617   driTextureObject * t = (driTextureObject *) texObj->DriverData;
618
619   assert( t ); /* this _should_ be true */
620   if ( t ) {
621      driSwapOutTextureObject( t );
622   }
623   else {
624      t = (driTextureObject *) r200AllocTexObj( texObj );
625      if (!t) {
626         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
627         return;
628      }
629   }
630
631   _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
632			     format, type, pixels, packing, texObj,
633			     texImage);
634
635   t->dirty_images[0] |= (1 << level);
636}
637
638
639static void r200TexImage2D( GLcontext *ctx, GLenum target, GLint level,
640                              GLint internalFormat,
641                              GLint width, GLint height, GLint border,
642                              GLenum format, GLenum type, const GLvoid *pixels,
643                              const struct gl_pixelstore_attrib *packing,
644                              struct gl_texture_object *texObj,
645                              struct gl_texture_image *texImage )
646{
647   driTextureObject * t = (driTextureObject *) texObj->DriverData;
648   GLuint face;
649
650   /* which cube face or ordinary 2D image */
651   switch (target) {
652   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
653   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
654   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
655   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
656   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
657   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
658      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
659      ASSERT(face < 6);
660      break;
661   default:
662      face = 0;
663   }
664
665   if ( t != NULL ) {
666      driSwapOutTextureObject( t );
667   }
668   else {
669      t = (driTextureObject *) r200AllocTexObj( texObj );
670      if (!t) {
671         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
672         return;
673      }
674   }
675
676   texImage->IsClientData = GL_FALSE;
677
678   if (r200ValidateClientStorage( ctx, target,
679				  internalFormat,
680				  width, height,
681				  format, type, pixels,
682				  packing, texObj, texImage)) {
683      if (R200_DEBUG & DEBUG_TEXTURE)
684	 fprintf(stderr, "%s: Using client storage\n", __FUNCTION__);
685   }
686   else {
687      if (R200_DEBUG & DEBUG_TEXTURE)
688	 fprintf(stderr, "%s: Using normal storage\n", __FUNCTION__);
689
690      /* Normal path: copy (to cached memory) and eventually upload
691       * via another copy to GART memory and then a blit...  Could
692       * eliminate one copy by going straight to (permanent) GART.
693       *
694       * Note, this will call r200ChooseTextureFormat.
695       */
696      _mesa_store_teximage2d(ctx, target, level, internalFormat,
697			     width, height, border, format, type, pixels,
698			     &ctx->Unpack, texObj, texImage);
699
700      t->dirty_images[face] |= (1 << level);
701   }
702}
703
704
705static void r200TexSubImage2D( GLcontext *ctx, GLenum target, GLint level,
706                                 GLint xoffset, GLint yoffset,
707                                 GLsizei width, GLsizei height,
708                                 GLenum format, GLenum type,
709                                 const GLvoid *pixels,
710                                 const struct gl_pixelstore_attrib *packing,
711                                 struct gl_texture_object *texObj,
712                                 struct gl_texture_image *texImage )
713{
714   driTextureObject * t = (driTextureObject *) texObj->DriverData;
715   GLuint face;
716
717   /* which cube face or ordinary 2D image */
718   switch (target) {
719   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
720   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
721   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
722   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
723   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
724   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
725      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
726      ASSERT(face < 6);
727      break;
728   default:
729      face = 0;
730   }
731
732   assert( t ); /* this _should_ be true */
733   if ( t ) {
734      driSwapOutTextureObject( t );
735   }
736   else {
737      t = (driTextureObject *) r200AllocTexObj( texObj );
738      if (!t) {
739         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
740         return;
741      }
742   }
743
744   _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
745			     height, format, type, pixels, packing, texObj,
746			     texImage);
747
748   t->dirty_images[face] |= (1 << level);
749}
750
751
752static void r200CompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level,
753                              GLint internalFormat,
754                              GLint width, GLint height, GLint border,
755                              GLsizei imageSize, const GLvoid *data,
756                              struct gl_texture_object *texObj,
757                              struct gl_texture_image *texImage )
758{
759   driTextureObject * t = (driTextureObject *) texObj->DriverData;
760   GLuint face;
761
762   /* which cube face or ordinary 2D image */
763   switch (target) {
764   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
765   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
766   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
767   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
768   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
769   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
770      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
771      ASSERT(face < 6);
772      break;
773   default:
774      face = 0;
775   }
776
777   if ( t != NULL ) {
778      driSwapOutTextureObject( t );
779   }
780   else {
781      t = (driTextureObject *) r200AllocTexObj( texObj );
782      if (!t) {
783         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
784         return;
785      }
786   }
787
788   texImage->IsClientData = GL_FALSE;
789/* can't call this, different parameters. Would never evaluate to true anyway currently
790   if (r200ValidateClientStorage( ctx, target,
791				  internalFormat,
792				  width, height,
793				  format, type, pixels,
794				  packing, texObj, texImage)) {
795      if (R200_DEBUG & DEBUG_TEXTURE)
796	 fprintf(stderr, "%s: Using client storage\n", __FUNCTION__);
797   }
798   else */{
799      if (R200_DEBUG & DEBUG_TEXTURE)
800	 fprintf(stderr, "%s: Using normal storage\n", __FUNCTION__);
801
802      /* Normal path: copy (to cached memory) and eventually upload
803       * via another copy to GART memory and then a blit...  Could
804       * eliminate one copy by going straight to (permanent) GART.
805       *
806       * Note, this will call r200ChooseTextureFormat.
807       */
808      _mesa_store_compressed_teximage2d(ctx, target, level, internalFormat, width,
809                                 height, border, imageSize, data, texObj, texImage);
810
811      t->dirty_images[face] |= (1 << level);
812   }
813}
814
815
816static void r200CompressedTexSubImage2D( GLcontext *ctx, GLenum target, GLint level,
817                                 GLint xoffset, GLint yoffset,
818                                 GLsizei width, GLsizei height,
819                                 GLenum format,
820                                 GLsizei imageSize, const GLvoid *data,
821                                 struct gl_texture_object *texObj,
822                                 struct gl_texture_image *texImage )
823{
824   driTextureObject * t = (driTextureObject *) texObj->DriverData;
825   GLuint face;
826
827
828   /* which cube face or ordinary 2D image */
829   switch (target) {
830   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
831   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
832   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
833   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
834   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
835   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
836      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
837      ASSERT(face < 6);
838      break;
839   default:
840      face = 0;
841   }
842
843   assert( t ); /* this _should_ be true */
844   if ( t ) {
845      driSwapOutTextureObject( t );
846   }
847   else {
848      t = (driTextureObject *) r200AllocTexObj( texObj );
849      if (!t) {
850         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage2D");
851         return;
852      }
853   }
854
855   _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
856                            height, format, imageSize, data, texObj, texImage);
857
858   t->dirty_images[face] |= (1 << level);
859}
860
861
862#if ENABLE_HW_3D_TEXTURE
863static void r200TexImage3D( GLcontext *ctx, GLenum target, GLint level,
864                            GLint internalFormat,
865                            GLint width, GLint height, GLint depth,
866                            GLint border,
867                            GLenum format, GLenum type, const GLvoid *pixels,
868                            const struct gl_pixelstore_attrib *packing,
869                            struct gl_texture_object *texObj,
870                            struct gl_texture_image *texImage )
871{
872   driTextureObject * t = (driTextureObject *) texObj->DriverData;
873
874   if ( t ) {
875      driSwapOutTextureObject( t );
876   }
877   else {
878      t = (driTextureObject *) r200AllocTexObj( texObj );
879      if (!t) {
880         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
881         return;
882      }
883   }
884
885   texImage->IsClientData = GL_FALSE;
886
887#if 0
888   if (r200ValidateClientStorage( ctx, target,
889				  internalFormat,
890				  width, height,
891				  format, type, pixels,
892				  packing, texObj, texImage)) {
893      if (R200_DEBUG & DEBUG_TEXTURE)
894	 fprintf(stderr, "%s: Using client storage\n", __FUNCTION__);
895   }
896   else
897#endif
898   {
899      if (R200_DEBUG & DEBUG_TEXTURE)
900	 fprintf(stderr, "%s: Using normal storage\n", __FUNCTION__);
901
902      /* Normal path: copy (to cached memory) and eventually upload
903       * via another copy to GART memory and then a blit...  Could
904       * eliminate one copy by going straight to (permanent) GART.
905       *
906       * Note, this will call r200ChooseTextureFormat.
907       */
908      _mesa_store_teximage3d(ctx, target, level, internalFormat,
909			     width, height, depth, border,
910                             format, type, pixels,
911			     &ctx->Unpack, texObj, texImage);
912
913      t->dirty_images[0] |= (1 << level);
914   }
915}
916#endif
917
918
919#if ENABLE_HW_3D_TEXTURE
920static void
921r200TexSubImage3D( GLcontext *ctx, GLenum target, GLint level,
922                   GLint xoffset, GLint yoffset, GLint zoffset,
923                   GLsizei width, GLsizei height, GLsizei depth,
924                   GLenum format, GLenum type,
925                   const GLvoid *pixels,
926                   const struct gl_pixelstore_attrib *packing,
927                   struct gl_texture_object *texObj,
928                   struct gl_texture_image *texImage )
929{
930   driTextureObject * t = (driTextureObject *) texObj->DriverData;
931
932/*     fprintf(stderr, "%s\n", __FUNCTION__); */
933
934   assert( t ); /* this _should_ be true */
935   if ( t ) {
936      driSwapOutTextureObject( t );
937   }
938   else {
939      t = (driTextureObject *) r200AllocTexObj( texObj );
940      if (!t) {
941         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage3D");
942         return;
943      }
944      texObj->DriverData = t;
945   }
946
947   _mesa_store_texsubimage3d(ctx, target, level, xoffset, yoffset, zoffset,
948                             width, height, depth,
949                             format, type, pixels, packing, texObj, texImage);
950
951   t->dirty_images[0] |= (1 << level);
952}
953#endif
954
955
956
957static void r200TexEnv( GLcontext *ctx, GLenum target,
958			  GLenum pname, const GLfloat *param )
959{
960   r200ContextPtr rmesa = R200_CONTEXT(ctx);
961   GLuint unit = ctx->Texture.CurrentUnit;
962   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
963
964   if ( R200_DEBUG & DEBUG_STATE ) {
965      fprintf( stderr, "%s( %s )\n",
966	       __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
967   }
968
969   /* This is incorrect: Need to maintain this data for each of
970    * GL_TEXTURE_{123}D, GL_TEXTURE_RECTANGLE_NV, etc, and switch
971    * between them according to _ReallyEnabled.
972    */
973   switch ( pname ) {
974   case GL_TEXTURE_ENV_COLOR: {
975      GLubyte c[4];
976      GLuint envColor;
977      UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
978      envColor = r200PackColor( 4, c[0], c[1], c[2], c[3] );
979      if ( rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] != envColor ) {
980	 R200_STATECHANGE( rmesa, tf );
981	 rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] = envColor;
982      }
983      break;
984   }
985
986   case GL_TEXTURE_LOD_BIAS_EXT: {
987      GLfloat bias, min;
988      GLuint b;
989      const int fixed_one = 0x8000000;
990
991      /* The R200's LOD bias is a signed 2's complement value with a
992       * range of -16.0 <= bias < 16.0.
993       *
994       * NOTE: Add a small bias to the bias for conform mipsel.c test.
995       */
996      bias = *param + .01;
997      min = driQueryOptionb (&rmesa->optionCache, "no_neg_lod_bias") ?
998	  0.0 : -16.0;
999      bias = CLAMP( bias, min, 16.0 );
1000      b = (int)(bias * fixed_one) & R200_LOD_BIAS_MASK;
1001
1002      if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] & R200_LOD_BIAS_MASK) != b ) {
1003	 R200_STATECHANGE( rmesa, tex[unit] );
1004	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] &= ~R200_LOD_BIAS_MASK;
1005	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] |= b;
1006      }
1007      break;
1008   }
1009   case GL_COORD_REPLACE_ARB:
1010      if (ctx->Point.PointSprite) {
1011	 R200_STATECHANGE( rmesa, spr );
1012	 if ((GLenum)param[0]) {
1013	    rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] |= R200_PS_GEN_TEX_0 << unit;
1014	 } else {
1015	    rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] &= ~(R200_PS_GEN_TEX_0 << unit);
1016	 }
1017      }
1018      break;
1019   default:
1020      return;
1021   }
1022}
1023
1024
1025/**
1026 * Changes variables and flags for a state update, which will happen at the
1027 * next UpdateTextureState
1028 */
1029
1030static void r200TexParameter( GLcontext *ctx, GLenum target,
1031				struct gl_texture_object *texObj,
1032				GLenum pname, const GLfloat *params )
1033{
1034   r200TexObjPtr t = (r200TexObjPtr) texObj->DriverData;
1035
1036   if ( R200_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
1037      fprintf( stderr, "%s( %s )\n", __FUNCTION__,
1038	       _mesa_lookup_enum_by_nr( pname ) );
1039   }
1040
1041   switch ( pname ) {
1042   case GL_TEXTURE_MIN_FILTER:
1043   case GL_TEXTURE_MAG_FILTER:
1044   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
1045      r200SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
1046      r200SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
1047      break;
1048
1049   case GL_TEXTURE_WRAP_S:
1050   case GL_TEXTURE_WRAP_T:
1051   case GL_TEXTURE_WRAP_R:
1052      r200SetTexWrap( t, texObj->WrapS, texObj->WrapT, texObj->WrapR );
1053      break;
1054
1055   case GL_TEXTURE_BORDER_COLOR:
1056      r200SetTexBorderColor( t, texObj->_BorderChan );
1057      break;
1058
1059   case GL_TEXTURE_BASE_LEVEL:
1060   case GL_TEXTURE_MAX_LEVEL:
1061   case GL_TEXTURE_MIN_LOD:
1062   case GL_TEXTURE_MAX_LOD:
1063      /* This isn't the most efficient solution but there doesn't appear to
1064       * be a nice alternative.  Since there's no LOD clamping,
1065       * we just have to rely on loading the right subset of mipmap levels
1066       * to simulate a clamped LOD.
1067       */
1068      driSwapOutTextureObject( (driTextureObject *) t );
1069      break;
1070
1071   default:
1072      return;
1073   }
1074
1075   /* Mark this texobj as dirty (one bit per tex unit)
1076    */
1077   t->dirty_state = TEX_ALL;
1078}
1079
1080
1081
1082static void r200BindTexture( GLcontext *ctx, GLenum target,
1083			       struct gl_texture_object *texObj )
1084{
1085   if ( R200_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
1086      fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, (void *)texObj,
1087	       ctx->Texture.CurrentUnit );
1088   }
1089
1090   if ( (target == GL_TEXTURE_1D)
1091	|| (target == GL_TEXTURE_2D)
1092#if ENABLE_HW_3D_TEXTURE
1093	|| (target == GL_TEXTURE_3D)
1094#endif
1095	|| (target == GL_TEXTURE_CUBE_MAP)
1096	|| (target == GL_TEXTURE_RECTANGLE_NV) ) {
1097      assert( texObj->DriverData != NULL );
1098   }
1099}
1100
1101
1102static void r200DeleteTexture( GLcontext *ctx,
1103				 struct gl_texture_object *texObj )
1104{
1105   r200ContextPtr rmesa = R200_CONTEXT(ctx);
1106   driTextureObject * t = (driTextureObject *) texObj->DriverData;
1107
1108   if ( R200_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
1109      fprintf( stderr, "%s( %p (target = %s) )\n", __FUNCTION__, (void *)texObj,
1110	       _mesa_lookup_enum_by_nr( texObj->Target ) );
1111   }
1112
1113   if ( t != NULL ) {
1114      if ( rmesa ) {
1115         R200_FIREVERTICES( rmesa );
1116      }
1117
1118      driDestroyTextureObject( t );
1119   }
1120   /* Free mipmap images and the texture object itself */
1121   _mesa_delete_texture_object(ctx, texObj);
1122}
1123
1124/* Need:
1125 *  - Same GEN_MODE for all active bits
1126 *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
1127 *  - STRQ presumably all supported (matrix means incoming R values
1128 *    can end up in STQ, this has implications for vertex support,
1129 *    presumably ok if maos is used, though?)
1130 *
1131 * Basically impossible to do this on the fly - just collect some
1132 * basic info & do the checks from ValidateState().
1133 */
1134static void r200TexGen( GLcontext *ctx,
1135			  GLenum coord,
1136			  GLenum pname,
1137			  const GLfloat *params )
1138{
1139   r200ContextPtr rmesa = R200_CONTEXT(ctx);
1140   GLuint unit = ctx->Texture.CurrentUnit;
1141   rmesa->recheck_texgen[unit] = GL_TRUE;
1142}
1143
1144
1145/**
1146 * Allocate a new texture object.
1147 * Called via ctx->Driver.NewTextureObject.
1148 * Note: this function will be called during context creation to
1149 * allocate the default texture objects.
1150 * Note: we could use containment here to 'derive' the driver-specific
1151 * texture object from the core mesa gl_texture_object.  Not done at this time.
1152 * Fixup MaxAnisotropy according to user preference.
1153 */
1154static struct gl_texture_object *
1155r200NewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
1156{
1157   r200ContextPtr rmesa = R200_CONTEXT(ctx);
1158   struct gl_texture_object *obj;
1159   obj = _mesa_new_texture_object(ctx, name, target);
1160   if (!obj)
1161      return NULL;
1162   obj->MaxAnisotropy = rmesa->initialMaxAnisotropy;
1163   r200AllocTexObj( obj );
1164   return obj;
1165}
1166
1167
1168void r200InitTextureFuncs( struct dd_function_table *functions )
1169{
1170   /* Note: we only plug in the functions we implement in the driver
1171    * since _mesa_init_driver_functions() was already called.
1172    */
1173   functions->ChooseTextureFormat	= r200ChooseTextureFormat;
1174   functions->TexImage1D		= r200TexImage1D;
1175   functions->TexImage2D		= r200TexImage2D;
1176#if ENABLE_HW_3D_TEXTURE
1177   functions->TexImage3D		= r200TexImage3D;
1178#else
1179   functions->TexImage3D		= _mesa_store_teximage3d;
1180#endif
1181   functions->TexSubImage1D		= r200TexSubImage1D;
1182   functions->TexSubImage2D		= r200TexSubImage2D;
1183#if ENABLE_HW_3D_TEXTURE
1184   functions->TexSubImage3D		= r200TexSubImage3D;
1185#else
1186   functions->TexSubImage3D		= _mesa_store_texsubimage3d;
1187#endif
1188   functions->NewTextureObject		= r200NewTextureObject;
1189   functions->BindTexture		= r200BindTexture;
1190   functions->DeleteTexture		= r200DeleteTexture;
1191   functions->IsTextureResident		= driIsTextureResident;
1192
1193   functions->TexEnv			= r200TexEnv;
1194   functions->TexParameter		= r200TexParameter;
1195   functions->TexGen			= r200TexGen;
1196
1197   functions->CompressedTexImage2D	= r200CompressedTexImage2D;
1198   functions->CompressedTexSubImage2D	= r200CompressedTexSubImage2D;
1199
1200   driInitTextureFormats();
1201
1202#if 000
1203   /* moved or obsolete code */
1204   r200ContextPtr rmesa = R200_CONTEXT(ctx);
1205   driInitTextureObjects( ctx, & rmesa->swapped,
1206			  DRI_TEXMGR_DO_TEXTURE_1D
1207			  | DRI_TEXMGR_DO_TEXTURE_2D );
1208
1209   /* Hack: r200NewTextureObject is not yet installed when the
1210    * default textures are created. Therefore set MaxAnisotropy of the
1211    * default 2D texture now. */
1212   ctx->Shared->Default2D->MaxAnisotropy = driQueryOptionf (&rmesa->optionCache,
1213							    "def_max_anisotropy");
1214#endif
1215}
1216