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