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