radeon_tex.c revision 4637235183b80963536f2364e4d50fcb894886dd
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/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_context.h"
47#include "radeon_state.h"
48#include "radeon_ioctl.h"
49#include "radeon_swtcl.h"
50#include "radeon_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 radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap )
65{
66   GLboolean  is_clamp = GL_FALSE;
67   GLboolean  is_clamp_to_border = GL_FALSE;
68
69   t->pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK | RADEON_BORDER_MODE_D3D);
70
71   switch ( swrap ) {
72   case GL_REPEAT:
73      t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
74      break;
75   case GL_CLAMP:
76      t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
77      is_clamp = GL_TRUE;
78      break;
79   case GL_CLAMP_TO_EDGE:
80      t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
81      break;
82   case GL_CLAMP_TO_BORDER:
83      t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
84      is_clamp_to_border = GL_TRUE;
85      break;
86   case GL_MIRRORED_REPEAT:
87      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR;
88      break;
89   case GL_MIRROR_CLAMP_EXT:
90      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
91      is_clamp = GL_TRUE;
92      break;
93   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
94      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_LAST;
95      break;
96   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
97      t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
98      is_clamp_to_border = GL_TRUE;
99      break;
100   default:
101      _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
102   }
103
104   switch ( twrap ) {
105   case GL_REPEAT:
106      t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
107      break;
108   case GL_CLAMP:
109      t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
110      is_clamp = GL_TRUE;
111      break;
112   case GL_CLAMP_TO_EDGE:
113      t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
114      break;
115   case GL_CLAMP_TO_BORDER:
116      t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
117      is_clamp_to_border = GL_TRUE;
118      break;
119   case GL_MIRRORED_REPEAT:
120      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR;
121      break;
122   case GL_MIRROR_CLAMP_EXT:
123      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
124      is_clamp = GL_TRUE;
125      break;
126   case GL_MIRROR_CLAMP_TO_EDGE_EXT:
127      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_LAST;
128      break;
129   case GL_MIRROR_CLAMP_TO_BORDER_EXT:
130      t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
131      is_clamp_to_border = GL_TRUE;
132      break;
133   default:
134      _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
135   }
136
137   if ( is_clamp_to_border ) {
138      t->pp_txfilter |= RADEON_BORDER_MODE_D3D;
139   }
140
141   t->border_fallback = (is_clamp && is_clamp_to_border);
142}
143
144static void radeonSetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
145{
146   t->pp_txfilter &= ~RADEON_MAX_ANISO_MASK;
147
148   if ( max == 1.0 ) {
149      t->pp_txfilter |= RADEON_MAX_ANISO_1_TO_1;
150   } else if ( max <= 2.0 ) {
151      t->pp_txfilter |= RADEON_MAX_ANISO_2_TO_1;
152   } else if ( max <= 4.0 ) {
153      t->pp_txfilter |= RADEON_MAX_ANISO_4_TO_1;
154   } else if ( max <= 8.0 ) {
155      t->pp_txfilter |= RADEON_MAX_ANISO_8_TO_1;
156   } else {
157      t->pp_txfilter |= RADEON_MAX_ANISO_16_TO_1;
158   }
159}
160
161/**
162 * Set the texture magnification and minification modes.
163 *
164 * \param t Texture whose filter modes are to be set
165 * \param minf Texture minification mode
166 * \param magf Texture magnification mode
167 */
168
169static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
170{
171   GLuint anisotropy = (t->pp_txfilter & RADEON_MAX_ANISO_MASK);
172
173   t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK);
174
175   /* r100 chips can't handle mipmaps/aniso for cubemap/volume textures */
176   if ( t->base.tObj->Target == GL_TEXTURE_CUBE_MAP ) {
177      switch ( minf ) {
178      case GL_NEAREST:
179      case GL_NEAREST_MIPMAP_NEAREST:
180      case GL_NEAREST_MIPMAP_LINEAR:
181	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
182	 break;
183      case GL_LINEAR:
184      case GL_LINEAR_MIPMAP_NEAREST:
185      case GL_LINEAR_MIPMAP_LINEAR:
186	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
187	 break;
188      default:
189	 break;
190      }
191   }
192   else if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
193      switch ( minf ) {
194      case GL_NEAREST:
195	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
196	 break;
197      case GL_LINEAR:
198	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
199	 break;
200      case GL_NEAREST_MIPMAP_NEAREST:
201	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
202	 break;
203      case GL_NEAREST_MIPMAP_LINEAR:
204	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
205	 break;
206      case GL_LINEAR_MIPMAP_NEAREST:
207	 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
208	 break;
209      case GL_LINEAR_MIPMAP_LINEAR:
210	 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
211	 break;
212      }
213   } else {
214      switch ( minf ) {
215      case GL_NEAREST:
216	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST;
217	 break;
218      case GL_LINEAR:
219	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_LINEAR;
220	 break;
221      case GL_NEAREST_MIPMAP_NEAREST:
222      case GL_LINEAR_MIPMAP_NEAREST:
223	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
224	 break;
225      case GL_NEAREST_MIPMAP_LINEAR:
226      case GL_LINEAR_MIPMAP_LINEAR:
227	 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
228	 break;
229      }
230   }
231
232   switch ( magf ) {
233   case GL_NEAREST:
234      t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
235      break;
236   case GL_LINEAR:
237      t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
238      break;
239   }
240}
241
242static void radeonSetTexBorderColor( radeonTexObjPtr t, GLubyte c[4] )
243{
244   t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
245}
246
247
248/**
249 * Allocate space for and load the mesa images into the texture memory block.
250 * This will happen before drawing with a new texture, or drawing with a
251 * texture after it was swapped out or teximaged again.
252 */
253
254static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj )
255{
256   radeonTexObjPtr t;
257
258   t = CALLOC_STRUCT( radeon_tex_obj );
259   texObj->DriverData = t;
260   if ( t != NULL ) {
261      if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
262	 fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, (void *)texObj, (void *)t );
263      }
264
265      /* Initialize non-image-dependent parts of the state:
266       */
267      t->base.tObj = texObj;
268      t->border_fallback = GL_FALSE;
269
270      t->pp_txfilter = RADEON_BORDER_MODE_OGL;
271      t->pp_txformat = (RADEON_TXFORMAT_ENDIAN_NO_SWAP |
272			RADEON_TXFORMAT_PERSPECTIVE_ENABLE);
273
274      make_empty_list( & t->base );
275
276      radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT );
277      radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
278      radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
279      radeonSetTexBorderColor( t, texObj->_BorderChan );
280   }
281
282   return t;
283}
284
285
286static const struct gl_texture_format *
287radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
288                           GLenum format, GLenum type )
289{
290   r100ContextPtr rmesa = R100_CONTEXT(ctx);
291   const GLboolean do32bpt =
292       ( rmesa->radeon.texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
293   const GLboolean force16bpt =
294       ( rmesa->radeon.texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
295   (void) format;
296
297   switch ( internalFormat ) {
298   case 4:
299   case GL_RGBA:
300   case GL_COMPRESSED_RGBA:
301      switch ( type ) {
302      case GL_UNSIGNED_INT_10_10_10_2:
303      case GL_UNSIGNED_INT_2_10_10_10_REV:
304	 return do32bpt ? _dri_texformat_argb8888 : _dri_texformat_argb1555;
305      case GL_UNSIGNED_SHORT_4_4_4_4:
306      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
307	 return _dri_texformat_argb4444;
308      case GL_UNSIGNED_SHORT_5_5_5_1:
309      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
310	 return _dri_texformat_argb1555;
311      default:
312         return do32bpt ? _dri_texformat_argb8888 : _dri_texformat_argb4444;
313      }
314
315   case 3:
316   case GL_RGB:
317   case GL_COMPRESSED_RGB:
318      switch ( type ) {
319      case GL_UNSIGNED_SHORT_4_4_4_4:
320      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
321	 return _dri_texformat_argb4444;
322      case GL_UNSIGNED_SHORT_5_5_5_1:
323      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
324	 return _dri_texformat_argb1555;
325      case GL_UNSIGNED_SHORT_5_6_5:
326      case GL_UNSIGNED_SHORT_5_6_5_REV:
327	 return _dri_texformat_rgb565;
328      default:
329         return do32bpt ? _dri_texformat_argb8888 : _dri_texformat_rgb565;
330      }
331
332   case GL_RGBA8:
333   case GL_RGB10_A2:
334   case GL_RGBA12:
335   case GL_RGBA16:
336      return !force16bpt ?
337	  _dri_texformat_argb8888 : _dri_texformat_argb4444;
338
339   case GL_RGBA4:
340   case GL_RGBA2:
341      return _dri_texformat_argb4444;
342
343   case GL_RGB5_A1:
344      return _dri_texformat_argb1555;
345
346   case GL_RGB8:
347   case GL_RGB10:
348   case GL_RGB12:
349   case GL_RGB16:
350      return !force16bpt ? _dri_texformat_argb8888 : _dri_texformat_rgb565;
351
352   case GL_RGB5:
353   case GL_RGB4:
354   case GL_R3_G3_B2:
355      return _dri_texformat_rgb565;
356
357   case GL_ALPHA:
358   case GL_ALPHA4:
359   case GL_ALPHA8:
360   case GL_ALPHA12:
361   case GL_ALPHA16:
362   case GL_COMPRESSED_ALPHA:
363      return _dri_texformat_a8;
364
365   case 1:
366   case GL_LUMINANCE:
367   case GL_LUMINANCE4:
368   case GL_LUMINANCE8:
369   case GL_LUMINANCE12:
370   case GL_LUMINANCE16:
371   case GL_COMPRESSED_LUMINANCE:
372      return _dri_texformat_l8;
373
374   case 2:
375   case GL_LUMINANCE_ALPHA:
376   case GL_LUMINANCE4_ALPHA4:
377   case GL_LUMINANCE6_ALPHA2:
378   case GL_LUMINANCE8_ALPHA8:
379   case GL_LUMINANCE12_ALPHA4:
380   case GL_LUMINANCE12_ALPHA12:
381   case GL_LUMINANCE16_ALPHA16:
382   case GL_COMPRESSED_LUMINANCE_ALPHA:
383      return _dri_texformat_al88;
384
385   case GL_INTENSITY:
386   case GL_INTENSITY4:
387   case GL_INTENSITY8:
388   case GL_INTENSITY12:
389   case GL_INTENSITY16:
390   case GL_COMPRESSED_INTENSITY:
391      return _dri_texformat_i8;
392
393   case GL_YCBCR_MESA:
394      if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
395          type == GL_UNSIGNED_BYTE)
396         return &_mesa_texformat_ycbcr;
397      else
398         return &_mesa_texformat_ycbcr_rev;
399
400   case GL_RGB_S3TC:
401   case GL_RGB4_S3TC:
402   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
403      return &_mesa_texformat_rgb_dxt1;
404
405   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
406      return &_mesa_texformat_rgba_dxt1;
407
408   case GL_RGBA_S3TC:
409   case GL_RGBA4_S3TC:
410   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
411      return &_mesa_texformat_rgba_dxt3;
412
413   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
414      return &_mesa_texformat_rgba_dxt5;
415
416   default:
417      _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__);
418      return NULL;
419   }
420
421   return NULL; /* never get here */
422}
423
424
425static void radeonTexImage1D( GLcontext *ctx, GLenum target, GLint level,
426                              GLint internalFormat,
427                              GLint width, GLint border,
428                              GLenum format, GLenum type, const GLvoid *pixels,
429                              const struct gl_pixelstore_attrib *packing,
430                              struct gl_texture_object *texObj,
431                              struct gl_texture_image *texImage )
432{
433   driTextureObject * t = (driTextureObject *) texObj->DriverData;
434
435   if ( t ) {
436      driSwapOutTextureObject( t );
437   }
438   else {
439      t = (driTextureObject *) radeonAllocTexObj( texObj );
440      if (!t) {
441         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
442         return;
443      }
444   }
445
446   /* Note, this will call ChooseTextureFormat */
447   _mesa_store_teximage1d(ctx, target, level, internalFormat,
448                          width, border, format, type, pixels,
449                          &ctx->Unpack, texObj, texImage);
450
451   t->dirty_images[0] |= (1 << level);
452}
453
454
455static void radeonTexSubImage1D( GLcontext *ctx, GLenum target, GLint level,
456                                 GLint xoffset,
457                                 GLsizei width,
458                                 GLenum format, GLenum type,
459                                 const GLvoid *pixels,
460                                 const struct gl_pixelstore_attrib *packing,
461                                 struct gl_texture_object *texObj,
462                                 struct gl_texture_image *texImage )
463{
464   driTextureObject * t = (driTextureObject *) texObj->DriverData;
465
466   assert( t ); /* this _should_ be true */
467   if ( t ) {
468      driSwapOutTextureObject( t );
469   }
470   else {
471      t = (driTextureObject *) radeonAllocTexObj( texObj );
472      if (!t) {
473         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
474         return;
475      }
476   }
477
478   _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
479			     format, type, pixels, packing, texObj,
480			     texImage);
481
482   t->dirty_images[0] |= (1 << level);
483}
484
485
486static void radeonTexImage2D( GLcontext *ctx, GLenum target, GLint level,
487                              GLint internalFormat,
488                              GLint width, GLint height, GLint border,
489                              GLenum format, GLenum type, const GLvoid *pixels,
490                              const struct gl_pixelstore_attrib *packing,
491                              struct gl_texture_object *texObj,
492                              struct gl_texture_image *texImage )
493{
494   driTextureObject * t = (driTextureObject *) texObj->DriverData;
495   GLuint face;
496
497   /* which cube face or ordinary 2D image */
498   switch (target) {
499   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
500   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
501   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
502   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
503   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
504   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
505      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
506      ASSERT(face < 6);
507      break;
508   default:
509      face = 0;
510   }
511
512   if ( t != NULL ) {
513      driSwapOutTextureObject( t );
514   }
515   else {
516      t = (driTextureObject *) radeonAllocTexObj( texObj );
517      if (!t) {
518         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
519         return;
520      }
521   }
522
523   /* Note, this will call ChooseTextureFormat */
524   _mesa_store_teximage2d(ctx, target, level, internalFormat,
525                          width, height, border, format, type, pixels,
526                          &ctx->Unpack, texObj, texImage);
527
528   t->dirty_images[face] |= (1 << level);
529}
530
531
532static void radeonTexSubImage2D( GLcontext *ctx, GLenum target, GLint level,
533                                 GLint xoffset, GLint yoffset,
534                                 GLsizei width, GLsizei height,
535                                 GLenum format, GLenum type,
536                                 const GLvoid *pixels,
537                                 const struct gl_pixelstore_attrib *packing,
538                                 struct gl_texture_object *texObj,
539                                 struct gl_texture_image *texImage )
540{
541   driTextureObject * t = (driTextureObject *) texObj->DriverData;
542   GLuint face;
543
544   /* which cube face or ordinary 2D image */
545   switch (target) {
546   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
547   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
548   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
549   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
550   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
551   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
552      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
553      ASSERT(face < 6);
554      break;
555   default:
556      face = 0;
557   }
558
559   assert( t ); /* this _should_ be true */
560   if ( t ) {
561      driSwapOutTextureObject( t );
562   }
563   else {
564      t = (driTextureObject *) radeonAllocTexObj( texObj );
565      if (!t) {
566         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
567         return;
568      }
569   }
570
571   _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
572			     height, format, type, pixels, packing, texObj,
573			     texImage);
574
575   t->dirty_images[face] |= (1 << level);
576}
577
578static void radeonCompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level,
579                              GLint internalFormat,
580                              GLint width, GLint height, GLint border,
581                              GLsizei imageSize, const GLvoid *data,
582                              struct gl_texture_object *texObj,
583                              struct gl_texture_image *texImage )
584{
585   driTextureObject * t = (driTextureObject *) texObj->DriverData;
586   GLuint face;
587
588   /* which cube face or ordinary 2D image */
589   switch (target) {
590   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
591   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
592   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
593   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
594   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
595   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
596      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
597      ASSERT(face < 6);
598      break;
599   default:
600      face = 0;
601   }
602
603   if ( t != NULL ) {
604      driSwapOutTextureObject( t );
605   }
606   else {
607      t = (driTextureObject *) radeonAllocTexObj( texObj );
608      if (!t) {
609         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
610         return;
611      }
612   }
613
614   /* Note, this will call ChooseTextureFormat */
615   _mesa_store_compressed_teximage2d(ctx, target, level, internalFormat, width,
616                                 height, border, imageSize, data, texObj, texImage);
617
618   t->dirty_images[face] |= (1 << level);
619}
620
621
622static void radeonCompressedTexSubImage2D( GLcontext *ctx, GLenum target, GLint level,
623                                 GLint xoffset, GLint yoffset,
624                                 GLsizei width, GLsizei height,
625                                 GLenum format,
626                                 GLsizei imageSize, const GLvoid *data,
627                                 struct gl_texture_object *texObj,
628                                 struct gl_texture_image *texImage )
629{
630   driTextureObject * t = (driTextureObject *) texObj->DriverData;
631   GLuint face;
632
633
634   /* which cube face or ordinary 2D image */
635   switch (target) {
636   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
637   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
638   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
639   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
640   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
641   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
642      face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
643      ASSERT(face < 6);
644      break;
645   default:
646      face = 0;
647   }
648
649   assert( t ); /* this _should_ be true */
650   if ( t ) {
651      driSwapOutTextureObject( t );
652   }
653   else {
654      t = (driTextureObject *) radeonAllocTexObj( texObj );
655      if (!t) {
656         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage2D");
657         return;
658      }
659   }
660
661   _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
662                                 height, format, imageSize, data, texObj, texImage);
663
664   t->dirty_images[face] |= (1 << level);
665}
666
667#define SCALED_FLOAT_TO_BYTE( x, scale ) \
668		(((GLuint)((255.0F / scale) * (x))) / 2)
669
670static void radeonTexEnv( GLcontext *ctx, GLenum target,
671			  GLenum pname, const GLfloat *param )
672{
673   r100ContextPtr rmesa = R100_CONTEXT(ctx);
674   GLuint unit = ctx->Texture.CurrentUnit;
675   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
676
677   if ( RADEON_DEBUG & DEBUG_STATE ) {
678      fprintf( stderr, "%s( %s )\n",
679	       __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
680   }
681
682   switch ( pname ) {
683   case GL_TEXTURE_ENV_COLOR: {
684      GLubyte c[4];
685      GLuint envColor;
686      UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
687      envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
688      if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
689	 RADEON_STATECHANGE( rmesa, tex[unit] );
690	 rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
691      }
692      break;
693   }
694
695   case GL_TEXTURE_LOD_BIAS_EXT: {
696      GLfloat bias, min;
697      GLuint b;
698
699      /* The Radeon's LOD bias is a signed 2's complement value with a
700       * range of -1.0 <= bias < 4.0.  We break this into two linear
701       * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping
702       * [0.0,4.0] to [0,127].
703       */
704      min = driQueryOptionb (&rmesa->radeon.optionCache, "no_neg_lod_bias") ?
705	  0.0 : -1.0;
706      bias = CLAMP( *param, min, 4.0 );
707      if ( bias == 0 ) {
708	 b = 0;
709      } else if ( bias > 0 ) {
710	 b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 4.0 )) << RADEON_LOD_BIAS_SHIFT;
711      } else {
712	 b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 1.0 )) << RADEON_LOD_BIAS_SHIFT;
713      }
714      if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] & RADEON_LOD_BIAS_MASK) != b ) {
715	 RADEON_STATECHANGE( rmesa, tex[unit] );
716	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] &= ~RADEON_LOD_BIAS_MASK;
717	 rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] |= (b & RADEON_LOD_BIAS_MASK);
718      }
719      break;
720   }
721
722   default:
723      return;
724   }
725}
726
727
728/**
729 * Changes variables and flags for a state update, which will happen at the
730 * next UpdateTextureState
731 */
732
733static void radeonTexParameter( GLcontext *ctx, GLenum target,
734				struct gl_texture_object *texObj,
735				GLenum pname, const GLfloat *params )
736{
737   radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
738
739   if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
740      fprintf( stderr, "%s( %s )\n", __FUNCTION__,
741	       _mesa_lookup_enum_by_nr( pname ) );
742   }
743
744   switch ( pname ) {
745   case GL_TEXTURE_MIN_FILTER:
746   case GL_TEXTURE_MAG_FILTER:
747   case GL_TEXTURE_MAX_ANISOTROPY_EXT:
748      radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
749      radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
750      break;
751
752   case GL_TEXTURE_WRAP_S:
753   case GL_TEXTURE_WRAP_T:
754      radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT );
755      break;
756
757   case GL_TEXTURE_BORDER_COLOR:
758      radeonSetTexBorderColor( t, texObj->_BorderChan );
759      break;
760
761   case GL_TEXTURE_BASE_LEVEL:
762   case GL_TEXTURE_MAX_LEVEL:
763   case GL_TEXTURE_MIN_LOD:
764   case GL_TEXTURE_MAX_LOD:
765      /* This isn't the most efficient solution but there doesn't appear to
766       * be a nice alternative.  Since there's no LOD clamping,
767       * we just have to rely on loading the right subset of mipmap levels
768       * to simulate a clamped LOD.
769       */
770      driSwapOutTextureObject( (driTextureObject *) t );
771      break;
772
773   default:
774      return;
775   }
776
777   /* Mark this texobj as dirty (one bit per tex unit)
778    */
779   t->dirty_state = R100_TEX_ALL;
780}
781
782
783static void radeonBindTexture( GLcontext *ctx, GLenum target,
784			       struct gl_texture_object *texObj )
785{
786   if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
787      fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, (void *)texObj,
788	       ctx->Texture.CurrentUnit );
789   }
790
791   assert( (target != GL_TEXTURE_1D && target != GL_TEXTURE_2D &&
792            target != GL_TEXTURE_RECTANGLE_NV && target != GL_TEXTURE_CUBE_MAP) ||
793           (texObj->DriverData != NULL) );
794}
795
796
797static void radeonDeleteTexture( GLcontext *ctx,
798				 struct gl_texture_object *texObj )
799{
800   r100ContextPtr rmesa = R100_CONTEXT(ctx);
801   driTextureObject * t = (driTextureObject *) texObj->DriverData;
802
803   if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
804      fprintf( stderr, "%s( %p (target = %s) )\n", __FUNCTION__, (void *)texObj,
805	       _mesa_lookup_enum_by_nr( texObj->Target ) );
806   }
807
808   if ( t != NULL ) {
809      if ( rmesa ) {
810         RADEON_FIREVERTICES( rmesa );
811      }
812
813      driDestroyTextureObject( t );
814   }
815
816   /* Free mipmap images and the texture object itself */
817   _mesa_delete_texture_object(ctx, texObj);
818}
819
820/* Need:
821 *  - Same GEN_MODE for all active bits
822 *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
823 *  - STRQ presumably all supported (matrix means incoming R values
824 *    can end up in STQ, this has implications for vertex support,
825 *    presumably ok if maos is used, though?)
826 *
827 * Basically impossible to do this on the fly - just collect some
828 * basic info & do the checks from ValidateState().
829 */
830static void radeonTexGen( GLcontext *ctx,
831			  GLenum coord,
832			  GLenum pname,
833			  const GLfloat *params )
834{
835   r100ContextPtr rmesa = R100_CONTEXT(ctx);
836   GLuint unit = ctx->Texture.CurrentUnit;
837   rmesa->recheck_texgen[unit] = GL_TRUE;
838}
839
840/**
841 * Allocate a new texture object.
842 * Called via ctx->Driver.NewTextureObject.
843 * Note: we could use containment here to 'derive' the driver-specific
844 * texture object from the core mesa gl_texture_object.  Not done at this time.
845 */
846static struct gl_texture_object *
847radeonNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
848{
849   r100ContextPtr rmesa = R100_CONTEXT(ctx);
850   struct gl_texture_object *obj;
851   obj = _mesa_new_texture_object(ctx, name, target);
852   if (!obj)
853      return NULL;
854   obj->MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
855   radeonAllocTexObj( obj );
856   return obj;
857}
858
859
860void radeonInitTextureFuncs( struct dd_function_table *functions )
861{
862   functions->ChooseTextureFormat	= radeonChooseTextureFormat;
863   functions->TexImage1D		= radeonTexImage1D;
864   functions->TexImage2D		= radeonTexImage2D;
865   functions->TexSubImage1D		= radeonTexSubImage1D;
866   functions->TexSubImage2D		= radeonTexSubImage2D;
867
868   functions->NewTextureObject		= radeonNewTextureObject;
869   functions->BindTexture		= radeonBindTexture;
870   functions->DeleteTexture		= radeonDeleteTexture;
871   functions->IsTextureResident		= driIsTextureResident;
872
873   functions->TexEnv			= radeonTexEnv;
874   functions->TexParameter		= radeonTexParameter;
875   functions->TexGen			= radeonTexGen;
876
877   functions->CompressedTexImage2D	= radeonCompressedTexImage2D;
878   functions->CompressedTexSubImage2D	= radeonCompressedTexSubImage2D;
879
880   driInitTextureFormats();
881}
882