Added support for EXT_texture_mirror_clamp.
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_tex.c
1 /* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */
2 /*
3 Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
4 VA Linux Systems Inc., Fremont, California.
5
6 All Rights Reserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29 /*
30 * Authors:
31 * Gareth Hughes <gareth@valinux.com>
32 * Brian Paul <brianp@valinux.com>
33 */
34
35 #include "glheader.h"
36 #include "imports.h"
37 #include "colormac.h"
38 #include "context.h"
39 #include "enums.h"
40 #include "image.h"
41 #include "simple_list.h"
42 #include "texformat.h"
43 #include "texstore.h"
44 #include "teximage.h"
45 #include "texobj.h"
46
47
48 #include "radeon_context.h"
49 #include "radeon_state.h"
50 #include "radeon_ioctl.h"
51 #include "radeon_swtcl.h"
52 #include "radeon_tex.h"
53
54 #include "xmlpool.h"
55
56
57
58 /**
59 * Set the texture wrap modes.
60 *
61 * \param t Texture object whose wrap modes are to be set
62 * \param swrap Wrap mode for the \a s texture coordinate
63 * \param twrap Wrap mode for the \a t texture coordinate
64 */
65
66 static void radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap )
67 {
68 GLboolean is_clamp = GL_FALSE;
69 GLboolean is_clamp_to_border = GL_FALSE;
70
71 t->pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK | RADEON_BORDER_MODE_D3D);
72
73 switch ( swrap ) {
74 case GL_REPEAT:
75 t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
76 break;
77 case GL_CLAMP:
78 t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
79 is_clamp = GL_TRUE;
80 break;
81 case GL_CLAMP_TO_EDGE:
82 t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
83 break;
84 case GL_CLAMP_TO_BORDER:
85 t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
86 is_clamp_to_border = GL_TRUE;
87 break;
88 case GL_MIRRORED_REPEAT:
89 t->pp_txfilter |= RADEON_CLAMP_S_MIRROR;
90 break;
91 case GL_MIRROR_CLAMP_EXT:
92 t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
93 is_clamp = GL_TRUE;
94 break;
95 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
96 t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_LAST;
97 break;
98 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
99 t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
100 is_clamp_to_border = GL_TRUE;
101 break;
102 default:
103 _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
104 }
105
106 switch ( twrap ) {
107 case GL_REPEAT:
108 t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
109 break;
110 case GL_CLAMP:
111 t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
112 is_clamp = GL_TRUE;
113 break;
114 case GL_CLAMP_TO_EDGE:
115 t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
116 break;
117 case GL_CLAMP_TO_BORDER:
118 t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
119 is_clamp_to_border = GL_TRUE;
120 break;
121 case GL_MIRRORED_REPEAT:
122 t->pp_txfilter |= RADEON_CLAMP_T_MIRROR;
123 break;
124 case GL_MIRROR_CLAMP_EXT:
125 t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
126 is_clamp = GL_TRUE;
127 break;
128 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
129 t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_LAST;
130 break;
131 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
132 t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
133 is_clamp_to_border = GL_TRUE;
134 break;
135 default:
136 _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
137 }
138
139 if ( is_clamp_to_border ) {
140 t->pp_txfilter |= RADEON_BORDER_MODE_D3D;
141 }
142
143 t->border_fallback = (is_clamp && is_clamp_to_border);
144 }
145
146 static void radeonSetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
147 {
148 t->pp_txfilter &= ~RADEON_MAX_ANISO_MASK;
149
150 if ( max == 1.0 ) {
151 t->pp_txfilter |= RADEON_MAX_ANISO_1_TO_1;
152 } else if ( max <= 2.0 ) {
153 t->pp_txfilter |= RADEON_MAX_ANISO_2_TO_1;
154 } else if ( max <= 4.0 ) {
155 t->pp_txfilter |= RADEON_MAX_ANISO_4_TO_1;
156 } else if ( max <= 8.0 ) {
157 t->pp_txfilter |= RADEON_MAX_ANISO_8_TO_1;
158 } else {
159 t->pp_txfilter |= RADEON_MAX_ANISO_16_TO_1;
160 }
161 }
162
163 /**
164 * Set the texture magnification and minification modes.
165 *
166 * \param t Texture whose filter modes are to be set
167 * \param minf Texture minification mode
168 * \param magf Texture magnification mode
169 */
170
171 static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
172 {
173 GLuint anisotropy = (t->pp_txfilter & RADEON_MAX_ANISO_MASK);
174
175 t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK);
176
177 if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
178 switch ( minf ) {
179 case GL_NEAREST:
180 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
181 break;
182 case GL_LINEAR:
183 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
184 break;
185 case GL_NEAREST_MIPMAP_NEAREST:
186 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
187 break;
188 case GL_NEAREST_MIPMAP_LINEAR:
189 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
190 break;
191 case GL_LINEAR_MIPMAP_NEAREST:
192 t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
193 break;
194 case GL_LINEAR_MIPMAP_LINEAR:
195 t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
196 break;
197 }
198 } else {
199 switch ( minf ) {
200 case GL_NEAREST:
201 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST;
202 break;
203 case GL_LINEAR:
204 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_LINEAR;
205 break;
206 case GL_NEAREST_MIPMAP_NEAREST:
207 case GL_LINEAR_MIPMAP_NEAREST:
208 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
209 break;
210 case GL_NEAREST_MIPMAP_LINEAR:
211 case GL_LINEAR_MIPMAP_LINEAR:
212 t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
213 break;
214 }
215 }
216
217 switch ( magf ) {
218 case GL_NEAREST:
219 t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
220 break;
221 case GL_LINEAR:
222 t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
223 break;
224 }
225 }
226
227 static void radeonSetTexBorderColor( radeonTexObjPtr t, GLubyte c[4] )
228 {
229 t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
230 }
231
232
233 /**
234 * Allocate space for and load the mesa images into the texture memory block.
235 * This will happen before drawing with a new texture, or drawing with a
236 * texture after it was swapped out or teximaged again.
237 */
238
239 static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj )
240 {
241 radeonTexObjPtr t;
242
243 t = CALLOC_STRUCT( radeon_tex_obj );
244 texObj->DriverData = t;
245 if ( t != NULL ) {
246 if ( RADEON_DEBUG & DEBUG_TEXTURE ) {
247 fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, texObj, t );
248 }
249
250 /* Initialize non-image-dependent parts of the state:
251 */
252 t->base.tObj = texObj;
253 t->border_fallback = GL_FALSE;
254
255 t->pp_txfilter = RADEON_BORDER_MODE_OGL;
256 t->pp_txformat = (RADEON_TXFORMAT_ENDIAN_NO_SWAP |
257 RADEON_TXFORMAT_PERSPECTIVE_ENABLE);
258
259 make_empty_list( & t->base );
260
261 radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT );
262 radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
263 radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
264 radeonSetTexBorderColor( t, texObj->_BorderChan );
265 }
266
267 return t;
268 }
269
270
271 static const struct gl_texture_format *
272 radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
273 GLenum format, GLenum type )
274 {
275 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
276 const GLboolean do32bpt =
277 ( rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
278 const GLboolean force16bpt =
279 ( rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
280 (void) format;
281
282 switch ( internalFormat ) {
283 case 4:
284 case GL_RGBA:
285 case GL_COMPRESSED_RGBA:
286 switch ( type ) {
287 case GL_UNSIGNED_INT_10_10_10_2:
288 case GL_UNSIGNED_INT_2_10_10_10_REV:
289 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
290 case GL_UNSIGNED_SHORT_4_4_4_4:
291 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
292 return &_mesa_texformat_argb4444;
293 case GL_UNSIGNED_SHORT_5_5_5_1:
294 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
295 return &_mesa_texformat_argb1555;
296 default:
297 return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_argb4444;
298 }
299
300 case 3:
301 case GL_RGB:
302 case GL_COMPRESSED_RGB:
303 switch ( type ) {
304 case GL_UNSIGNED_SHORT_4_4_4_4:
305 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
306 return &_mesa_texformat_argb4444;
307 case GL_UNSIGNED_SHORT_5_5_5_1:
308 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
309 return &_mesa_texformat_argb1555;
310 case GL_UNSIGNED_SHORT_5_6_5:
311 case GL_UNSIGNED_SHORT_5_6_5_REV:
312 return &_mesa_texformat_rgb565;
313 default:
314 return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_rgb565;
315 }
316
317 case GL_RGBA8:
318 case GL_RGB10_A2:
319 case GL_RGBA12:
320 case GL_RGBA16:
321 return !force16bpt ?
322 &_mesa_texformat_rgba8888 : &_mesa_texformat_argb4444;
323
324 case GL_RGBA4:
325 case GL_RGBA2:
326 return &_mesa_texformat_argb4444;
327
328 case GL_RGB5_A1:
329 return &_mesa_texformat_argb1555;
330
331 case GL_RGB8:
332 case GL_RGB10:
333 case GL_RGB12:
334 case GL_RGB16:
335 return !force16bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_rgb565;
336
337 case GL_RGB5:
338 case GL_RGB4:
339 case GL_R3_G3_B2:
340 return &_mesa_texformat_rgb565;
341
342 case GL_ALPHA:
343 case GL_ALPHA4:
344 case GL_ALPHA8:
345 case GL_ALPHA12:
346 case GL_ALPHA16:
347 case GL_COMPRESSED_ALPHA:
348 return &_mesa_texformat_al88;
349
350 case 1:
351 case GL_LUMINANCE:
352 case GL_LUMINANCE4:
353 case GL_LUMINANCE8:
354 case GL_LUMINANCE12:
355 case GL_LUMINANCE16:
356 case GL_COMPRESSED_LUMINANCE:
357 return &_mesa_texformat_al88;
358
359 case 2:
360 case GL_LUMINANCE_ALPHA:
361 case GL_LUMINANCE4_ALPHA4:
362 case GL_LUMINANCE6_ALPHA2:
363 case GL_LUMINANCE8_ALPHA8:
364 case GL_LUMINANCE12_ALPHA4:
365 case GL_LUMINANCE12_ALPHA12:
366 case GL_LUMINANCE16_ALPHA16:
367 case GL_COMPRESSED_LUMINANCE_ALPHA:
368 return &_mesa_texformat_al88;
369
370 case GL_INTENSITY:
371 case GL_INTENSITY4:
372 case GL_INTENSITY8:
373 case GL_INTENSITY12:
374 case GL_INTENSITY16:
375 case GL_COMPRESSED_INTENSITY:
376 return &_mesa_texformat_i8;
377
378 case GL_YCBCR_MESA:
379 if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
380 type == GL_UNSIGNED_BYTE)
381 return &_mesa_texformat_ycbcr;
382 else
383 return &_mesa_texformat_ycbcr_rev;
384
385 default:
386 _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__);
387 return NULL;
388 }
389
390 return NULL; /* never get here */
391 }
392
393
394 static void radeonTexImage1D( GLcontext *ctx, GLenum target, GLint level,
395 GLint internalFormat,
396 GLint width, GLint border,
397 GLenum format, GLenum type, const GLvoid *pixels,
398 const struct gl_pixelstore_attrib *packing,
399 struct gl_texture_object *texObj,
400 struct gl_texture_image *texImage )
401 {
402 driTextureObject * t = (driTextureObject *) texObj->DriverData;
403
404 if ( t ) {
405 driSwapOutTextureObject( t );
406 }
407 else {
408 t = (driTextureObject *) radeonAllocTexObj( texObj );
409 if (!t) {
410 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
411 return;
412 }
413 }
414
415 /* Note, this will call ChooseTextureFormat */
416 _mesa_store_teximage1d(ctx, target, level, internalFormat,
417 width, border, format, type, pixels,
418 &ctx->Unpack, texObj, texImage);
419
420 t->dirty_images[0] |= (1 << level);
421 }
422
423
424 static void radeonTexSubImage1D( GLcontext *ctx, GLenum target, GLint level,
425 GLint xoffset,
426 GLsizei width,
427 GLenum format, GLenum type,
428 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 assert( t ); /* this _should_ be true */
436 if ( t ) {
437 driSwapOutTextureObject( t );
438 }
439 else {
440 t = (driTextureObject *) radeonAllocTexObj( texObj );
441 if (!t) {
442 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
443 return;
444 }
445 }
446
447 _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
448 format, type, pixels, packing, texObj,
449 texImage);
450
451 t->dirty_images[0] |= (1 << level);
452 }
453
454
455 static void radeonTexImage2D( GLcontext *ctx, GLenum target, GLint level,
456 GLint internalFormat,
457 GLint width, GLint height, GLint border,
458 GLenum format, GLenum type, const GLvoid *pixels,
459 const struct gl_pixelstore_attrib *packing,
460 struct gl_texture_object *texObj,
461 struct gl_texture_image *texImage )
462 {
463 driTextureObject * t = (driTextureObject *) texObj->DriverData;
464 GLuint face;
465
466 /* which cube face or ordinary 2D image */
467 switch (target) {
468 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
469 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
470 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
471 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
472 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
473 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
474 face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
475 ASSERT(face < 6);
476 break;
477 default:
478 face = 0;
479 }
480
481 if ( t != NULL ) {
482 driSwapOutTextureObject( t );
483 }
484 else {
485 t = (driTextureObject *) radeonAllocTexObj( texObj );
486 if (!t) {
487 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
488 return;
489 }
490 }
491
492 /* Note, this will call ChooseTextureFormat */
493 _mesa_store_teximage2d(ctx, target, level, internalFormat,
494 width, height, border, format, type, pixels,
495 &ctx->Unpack, texObj, texImage);
496
497 t->dirty_images[face] |= (1 << level);
498 }
499
500
501 static void radeonTexSubImage2D( GLcontext *ctx, GLenum target, GLint level,
502 GLint xoffset, GLint yoffset,
503 GLsizei width, GLsizei height,
504 GLenum format, GLenum type,
505 const GLvoid *pixels,
506 const struct gl_pixelstore_attrib *packing,
507 struct gl_texture_object *texObj,
508 struct gl_texture_image *texImage )
509 {
510 driTextureObject * t = (driTextureObject *) texObj->DriverData;
511 GLuint face;
512
513
514 /* which cube face or ordinary 2D image */
515 switch (target) {
516 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
517 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
518 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
519 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
520 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
521 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
522 face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
523 ASSERT(face < 6);
524 break;
525 default:
526 face = 0;
527 }
528
529 assert( t ); /* this _should_ be true */
530 if ( t ) {
531 driSwapOutTextureObject( t );
532 }
533 else {
534 t = (driTextureObject *) radeonAllocTexObj( texObj );
535 if (!t) {
536 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
537 return;
538 }
539 }
540
541 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
542 height, format, type, pixels, packing, texObj,
543 texImage);
544
545 t->dirty_images[face] |= (1 << level);
546 }
547
548
549
550 #define SCALED_FLOAT_TO_BYTE( x, scale ) \
551 (((GLuint)((255.0F / scale) * (x))) / 2)
552
553 static void radeonTexEnv( GLcontext *ctx, GLenum target,
554 GLenum pname, const GLfloat *param )
555 {
556 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
557 GLuint unit = ctx->Texture.CurrentUnit;
558 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
559
560 if ( RADEON_DEBUG & DEBUG_STATE ) {
561 fprintf( stderr, "%s( %s )\n",
562 __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
563 }
564
565 switch ( pname ) {
566 case GL_TEXTURE_ENV_COLOR: {
567 GLubyte c[4];
568 GLuint envColor;
569 UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
570 envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
571 if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
572 RADEON_STATECHANGE( rmesa, tex[unit] );
573 rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
574 }
575 break;
576 }
577
578 case GL_TEXTURE_LOD_BIAS_EXT: {
579 GLfloat bias, min;
580 GLuint b;
581
582 /* The Radeon's LOD bias is a signed 2's complement value with a
583 * range of -1.0 <= bias < 4.0. We break this into two linear
584 * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping
585 * [0.0,4.0] to [0,127].
586 */
587 min = driQueryOptionb (&rmesa->optionCache, "no_neg_lod_bias") ?
588 0.0 : -1.0;
589 bias = CLAMP( *param, min, 4.0 );
590 if ( bias == 0 ) {
591 b = 0;
592 } else if ( bias > 0 ) {
593 b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 4.0 )) << RADEON_LOD_BIAS_SHIFT;
594 } else {
595 b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 1.0 )) << RADEON_LOD_BIAS_SHIFT;
596 }
597 if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] & RADEON_LOD_BIAS_MASK) != b ) {
598 RADEON_STATECHANGE( rmesa, tex[unit] );
599 rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] &= ~RADEON_LOD_BIAS_MASK;
600 rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] |= (b & RADEON_LOD_BIAS_MASK);
601 }
602 break;
603 }
604
605 default:
606 return;
607 }
608 }
609
610
611 /**
612 * Changes variables and flags for a state update, which will happen at the
613 * next UpdateTextureState
614 */
615
616 static void radeonTexParameter( GLcontext *ctx, GLenum target,
617 struct gl_texture_object *texObj,
618 GLenum pname, const GLfloat *params )
619 {
620 radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData;
621
622 if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
623 fprintf( stderr, "%s( %s )\n", __FUNCTION__,
624 _mesa_lookup_enum_by_nr( pname ) );
625 }
626
627 if ( ( target != GL_TEXTURE_2D ) &&
628 ( target != GL_TEXTURE_1D ) )
629 return;
630
631 switch ( pname ) {
632 case GL_TEXTURE_MIN_FILTER:
633 case GL_TEXTURE_MAG_FILTER:
634 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
635 radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
636 radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
637 break;
638
639 case GL_TEXTURE_WRAP_S:
640 case GL_TEXTURE_WRAP_T:
641 radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT );
642 break;
643
644 case GL_TEXTURE_BORDER_COLOR:
645 radeonSetTexBorderColor( t, texObj->_BorderChan );
646 break;
647
648 case GL_TEXTURE_BASE_LEVEL:
649 case GL_TEXTURE_MAX_LEVEL:
650 case GL_TEXTURE_MIN_LOD:
651 case GL_TEXTURE_MAX_LOD:
652 /* This isn't the most efficient solution but there doesn't appear to
653 * be a nice alternative. Since there's no LOD clamping,
654 * we just have to rely on loading the right subset of mipmap levels
655 * to simulate a clamped LOD.
656 */
657 driSwapOutTextureObject( (driTextureObject *) t );
658 break;
659
660 default:
661 return;
662 }
663
664 /* Mark this texobj as dirty (one bit per tex unit)
665 */
666 t->dirty_state = TEX_ALL;
667 }
668
669
670
671 static void radeonBindTexture( GLcontext *ctx, GLenum target,
672 struct gl_texture_object *texObj )
673 {
674 if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
675 fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, texObj,
676 ctx->Texture.CurrentUnit );
677 }
678
679 if ( target == GL_TEXTURE_2D || target == GL_TEXTURE_1D ) {
680 if ( texObj->DriverData == NULL ) {
681 radeonAllocTexObj( texObj );
682 }
683 }
684 }
685
686 static void radeonDeleteTexture( GLcontext *ctx,
687 struct gl_texture_object *texObj )
688 {
689 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
690 driTextureObject * t = (driTextureObject *) texObj->DriverData;
691
692 if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
693 fprintf( stderr, "%s( %p (target = %s) )\n", __FUNCTION__, texObj,
694 _mesa_lookup_enum_by_nr( texObj->Target ) );
695 }
696
697 if ( t != NULL ) {
698 if ( rmesa ) {
699 RADEON_FIREVERTICES( rmesa );
700 }
701
702 driDestroyTextureObject( t );
703 }
704
705 /* Free mipmap images and the texture object itself */
706 _mesa_delete_texture_object(ctx, texObj);
707 }
708
709 /* Need:
710 * - Same GEN_MODE for all active bits
711 * - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
712 * - STRQ presumably all supported (matrix means incoming R values
713 * can end up in STQ, this has implications for vertex support,
714 * presumably ok if maos is used, though?)
715 *
716 * Basically impossible to do this on the fly - just collect some
717 * basic info & do the checks from ValidateState().
718 */
719 static void radeonTexGen( GLcontext *ctx,
720 GLenum coord,
721 GLenum pname,
722 const GLfloat *params )
723 {
724 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
725 GLuint unit = ctx->Texture.CurrentUnit;
726 rmesa->recheck_texgen[unit] = GL_TRUE;
727 }
728
729 /* Fixup MaxAnisotropy according to user preference.
730 */
731 static struct gl_texture_object *radeonNewTextureObject ( GLcontext *ctx,
732 GLuint name,
733 GLenum target ) {
734 struct gl_texture_object *obj;
735 obj = _mesa_new_texture_object (ctx, name, target);
736 obj->MaxAnisotropy = driQueryOptionf (&RADEON_CONTEXT(ctx)->optionCache,
737 "def_max_anisotropy");
738 return obj;
739 }
740
741
742 void radeonInitTextureFuncs( GLcontext *ctx )
743 {
744 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
745
746
747 ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat;
748 ctx->Driver.TexImage1D = radeonTexImage1D;
749 ctx->Driver.TexImage2D = radeonTexImage2D;
750 ctx->Driver.TexImage3D = _mesa_store_teximage3d;
751 ctx->Driver.TexSubImage1D = radeonTexSubImage1D;
752 ctx->Driver.TexSubImage2D = radeonTexSubImage2D;
753 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
754 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
755 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
756 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
757 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
758 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
759 ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
760
761 ctx->Driver.NewTextureObject = radeonNewTextureObject;
762 ctx->Driver.BindTexture = radeonBindTexture;
763 ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
764 ctx->Driver.DeleteTexture = radeonDeleteTexture;
765 ctx->Driver.IsTextureResident = driIsTextureResident;
766 ctx->Driver.PrioritizeTexture = NULL;
767 ctx->Driver.ActiveTexture = NULL;
768 ctx->Driver.UpdateTexturePalette = NULL;
769
770 ctx->Driver.TexEnv = radeonTexEnv;
771 ctx->Driver.TexParameter = radeonTexParameter;
772 ctx->Driver.TexGen = radeonTexGen;
773
774 driInitTextureObjects( ctx, & rmesa->swapped,
775 DRI_TEXMGR_DO_TEXTURE_1D
776 | DRI_TEXMGR_DO_TEXTURE_2D );
777
778 /* Hack: radeonNewTextureObject is not yet installed when the
779 * default textures are created. Therefore set MaxAnisotropy of the
780 * default 2D texture now. */
781 ctx->Shared->Default2D->MaxAnisotropy = driQueryOptionf (&rmesa->optionCache,
782 "def_max_anisotropy");
783 }