Merge commit 'origin/gallium-0.1'
[mesa.git] / src / mesa / drivers / dri / r128 / r128_tex.c
1 /**************************************************************************
2
3 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
4 Cedar Park, Texas.
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Gareth Hughes <gareth@valinux.com>
31 * Kevin E. Martin <martin@valinux.com>
32 * Brian Paul <brianp@valinux.com>
33 */
34
35 #include "r128_context.h"
36 #include "r128_state.h"
37 #include "r128_ioctl.h"
38 #include "r128_tris.h"
39 #include "r128_tex.h"
40 #include "r128_texobj.h"
41
42 #include "main/context.h"
43 #include "main/macros.h"
44 #include "main/simple_list.h"
45 #include "main/enums.h"
46 #include "main/texstore.h"
47 #include "main/texformat.h"
48 #include "main/teximage.h"
49 #include "main/texobj.h"
50 #include "main/imports.h"
51 #include "main/colormac.h"
52 #include "main/texobj.h"
53
54 #include "xmlpool.h"
55
56 #define TEX_0 1
57 #define TEX_1 2
58
59
60 /**
61 * Set the texture wrap modes. Currently \c GL_REPEAT, \c GL_CLAMP,
62 * \c GL_CLAMP_TO_EDGE, and \c GL_MIRRORED_REPEAT are supported.
63 *
64 * \param t Texture object whose wrap modes are to be set
65 * \param swrap Wrap mode for the \a s texture coordinate
66 * \param twrap Wrap mode for the \a t texture coordinate
67 */
68 static void r128SetTexWrap( r128TexObjPtr t, GLenum swrap, GLenum twrap )
69 {
70 t->setup.tex_cntl &= ~(R128_TEX_CLAMP_S_MASK | R128_TEX_CLAMP_T_MASK);
71
72 switch ( swrap ) {
73 case GL_CLAMP:
74 t->setup.tex_cntl |= R128_TEX_CLAMP_S_BORDER_COLOR;
75 break;
76 case GL_CLAMP_TO_EDGE:
77 t->setup.tex_cntl |= R128_TEX_CLAMP_S_CLAMP;
78 break;
79 case GL_REPEAT:
80 t->setup.tex_cntl |= R128_TEX_CLAMP_S_WRAP;
81 break;
82 case GL_MIRRORED_REPEAT:
83 t->setup.tex_cntl |= R128_TEX_CLAMP_S_MIRROR;
84 break;
85 }
86
87 switch ( twrap ) {
88 case GL_CLAMP:
89 t->setup.tex_cntl |= R128_TEX_CLAMP_T_BORDER_COLOR;
90 break;
91 case GL_CLAMP_TO_EDGE:
92 t->setup.tex_cntl |= R128_TEX_CLAMP_T_CLAMP;
93 break;
94 case GL_REPEAT:
95 t->setup.tex_cntl |= R128_TEX_CLAMP_T_WRAP;
96 break;
97 case GL_MIRRORED_REPEAT:
98 t->setup.tex_cntl |= R128_TEX_CLAMP_T_MIRROR;
99 break;
100 }
101 }
102
103 static void r128SetTexFilter( r128TexObjPtr t, GLenum minf, GLenum magf )
104 {
105 t->setup.tex_cntl &= ~(R128_MIN_BLEND_MASK | R128_MAG_BLEND_MASK);
106
107 switch ( minf ) {
108 case GL_NEAREST:
109 t->setup.tex_cntl |= R128_MIN_BLEND_NEAREST;
110 break;
111 case GL_LINEAR:
112 t->setup.tex_cntl |= R128_MIN_BLEND_LINEAR;
113 break;
114 case GL_NEAREST_MIPMAP_NEAREST:
115 t->setup.tex_cntl |= R128_MIN_BLEND_MIPNEAREST;
116 break;
117 case GL_LINEAR_MIPMAP_NEAREST:
118 t->setup.tex_cntl |= R128_MIN_BLEND_MIPLINEAR;
119 break;
120 case GL_NEAREST_MIPMAP_LINEAR:
121 t->setup.tex_cntl |= R128_MIN_BLEND_LINEARMIPNEAREST;
122 break;
123 case GL_LINEAR_MIPMAP_LINEAR:
124 t->setup.tex_cntl |= R128_MIN_BLEND_LINEARMIPLINEAR;
125 break;
126 }
127
128 switch ( magf ) {
129 case GL_NEAREST:
130 t->setup.tex_cntl |= R128_MAG_BLEND_NEAREST;
131 break;
132 case GL_LINEAR:
133 t->setup.tex_cntl |= R128_MAG_BLEND_LINEAR;
134 break;
135 }
136 }
137
138 static void r128SetTexBorderColor( r128TexObjPtr t, GLubyte c[4] )
139 {
140 t->setup.tex_border_color = r128PackColor( 4, c[0], c[1], c[2], c[3] );
141 }
142
143
144 static r128TexObjPtr r128AllocTexObj( struct gl_texture_object *texObj )
145 {
146 r128TexObjPtr t;
147
148 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
149 fprintf( stderr, "%s( %p )\n", __FUNCTION__, (void *) texObj );
150 }
151
152 t = (r128TexObjPtr) CALLOC_STRUCT( r128_tex_obj );
153 texObj->DriverData = t;
154 if ( t != NULL ) {
155
156 /* Initialize non-image-dependent parts of the state:
157 */
158 t->base.tObj = texObj;
159
160 /* FIXME Something here to set initial values for other parts of
161 * FIXME t->setup?
162 */
163
164 make_empty_list( (driTextureObject *) t );
165
166 r128SetTexWrap( t, texObj->WrapS, texObj->WrapT );
167 r128SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
168 r128SetTexBorderColor( t, texObj->_BorderChan );
169 }
170
171 return t;
172 }
173
174
175 /* Called by the _mesa_store_teximage[123]d() functions. */
176 static const struct gl_texture_format *
177 r128ChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
178 GLenum format, GLenum type )
179 {
180 r128ContextPtr rmesa = R128_CONTEXT(ctx);
181 const GLboolean do32bpt =
182 ( rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
183 const GLboolean force16bpt =
184 ( rmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
185 (void) format;
186 (void) type;
187
188 switch ( internalFormat ) {
189 /* non-sized formats with alpha */
190 case GL_INTENSITY:
191 case GL_COMPRESSED_INTENSITY:
192 case GL_ALPHA:
193 case GL_COMPRESSED_ALPHA:
194 case 2:
195 case GL_LUMINANCE_ALPHA:
196 case GL_COMPRESSED_LUMINANCE_ALPHA:
197 case 4:
198 case GL_RGBA:
199 case GL_COMPRESSED_RGBA:
200 if (do32bpt)
201 return _dri_texformat_argb8888;
202 else
203 return _dri_texformat_argb4444;
204
205 /* 16-bit formats with alpha */
206 case GL_INTENSITY4:
207 case GL_ALPHA4:
208 case GL_LUMINANCE4_ALPHA4:
209 case GL_RGBA2:
210 case GL_RGBA4:
211 return _dri_texformat_argb4444;
212
213 /* 32-bit formats with alpha */
214 case GL_INTENSITY8:
215 case GL_INTENSITY12:
216 case GL_INTENSITY16:
217 case GL_ALPHA8:
218 case GL_ALPHA12:
219 case GL_ALPHA16:
220 case GL_LUMINANCE6_ALPHA2:
221 case GL_LUMINANCE8_ALPHA8:
222 case GL_LUMINANCE12_ALPHA4:
223 case GL_LUMINANCE12_ALPHA12:
224 case GL_LUMINANCE16_ALPHA16:
225 case GL_RGB5_A1:
226 case GL_RGBA8:
227 case GL_RGB10_A2:
228 case GL_RGBA12:
229 case GL_RGBA16:
230 if (!force16bpt)
231 return _dri_texformat_argb8888;
232 else
233 return _dri_texformat_argb4444;
234
235 /* non-sized formats without alpha */
236 case 1:
237 case GL_LUMINANCE:
238 case GL_COMPRESSED_LUMINANCE:
239 case 3:
240 case GL_RGB:
241 case GL_COMPRESSED_RGB:
242 if (do32bpt)
243 return _dri_texformat_argb8888;
244 else
245 return _dri_texformat_rgb565;
246
247 /* 16-bit formats without alpha */
248 case GL_LUMINANCE4:
249 case GL_R3_G3_B2:
250 case GL_RGB4:
251 case GL_RGB5:
252 return _dri_texformat_rgb565;
253
254 /* 32-bit formats without alpha */
255 case GL_LUMINANCE8:
256 case GL_LUMINANCE12:
257 case GL_LUMINANCE16:
258 case GL_RGB8:
259 case GL_RGB10:
260 case GL_RGB12:
261 case GL_RGB16:
262 if (!force16bpt)
263 return _dri_texformat_argb8888;
264 else
265 return _dri_texformat_rgb565;
266
267 /* color-indexed formats */
268 case GL_COLOR_INDEX:
269 case GL_COLOR_INDEX1_EXT:
270 case GL_COLOR_INDEX2_EXT:
271 case GL_COLOR_INDEX4_EXT:
272 case GL_COLOR_INDEX8_EXT:
273 case GL_COLOR_INDEX12_EXT:
274 case GL_COLOR_INDEX16_EXT:
275 return _dri_texformat_ci8;
276
277 case GL_YCBCR_MESA:
278 if (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
279 type == GL_UNSIGNED_BYTE)
280 return &_mesa_texformat_ycbcr;
281 else
282 return &_mesa_texformat_ycbcr_rev;
283
284 default:
285 _mesa_problem( ctx, "unexpected format in %s", __FUNCTION__ );
286 return NULL;
287 }
288 }
289
290
291 static void r128TexImage1D( GLcontext *ctx, GLenum target, GLint level,
292 GLint internalFormat,
293 GLint width, GLint border,
294 GLenum format, GLenum type, const GLvoid *pixels,
295 const struct gl_pixelstore_attrib *packing,
296 struct gl_texture_object *texObj,
297 struct gl_texture_image *texImage )
298 {
299 driTextureObject * t = (driTextureObject *) texObj->DriverData;
300
301 if ( t ) {
302 driSwapOutTextureObject( t );
303 }
304 else {
305 t = (driTextureObject *) r128AllocTexObj(texObj);
306 if (!t) {
307 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
308 return;
309 }
310 }
311
312 /* Note, this will call r128ChooseTextureFormat */
313 _mesa_store_teximage1d( ctx, target, level, internalFormat,
314 width, border, format, type,
315 pixels, packing, texObj, texImage );
316
317 t->dirty_images[0] |= (1 << level);
318 }
319
320
321 static void r128TexSubImage1D( GLcontext *ctx,
322 GLenum target,
323 GLint level,
324 GLint xoffset,
325 GLsizei width,
326 GLenum format, GLenum type,
327 const GLvoid *pixels,
328 const struct gl_pixelstore_attrib *packing,
329 struct gl_texture_object *texObj,
330 struct gl_texture_image *texImage )
331 {
332 driTextureObject * t = (driTextureObject *) texObj->DriverData;
333
334 assert( t ); /* this _should_ be true */
335 if ( t ) {
336 driSwapOutTextureObject( t );
337 }
338 else {
339 t = (driTextureObject *) r128AllocTexObj(texObj);
340 if (!t) {
341 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
342 return;
343 }
344 }
345
346 _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
347 format, type, pixels, packing, texObj,
348 texImage);
349
350 t->dirty_images[0] |= (1 << level);
351 }
352
353
354 static void r128TexImage2D( GLcontext *ctx, GLenum target, GLint level,
355 GLint internalFormat,
356 GLint width, GLint height, GLint border,
357 GLenum format, GLenum type, const GLvoid *pixels,
358 const struct gl_pixelstore_attrib *packing,
359 struct gl_texture_object *texObj,
360 struct gl_texture_image *texImage )
361 {
362 driTextureObject * t = (driTextureObject *) texObj->DriverData;
363
364 if ( t ) {
365 driSwapOutTextureObject( (driTextureObject *) t );
366 }
367 else {
368 t = (driTextureObject *) r128AllocTexObj(texObj);
369 if (!t) {
370 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
371 return;
372 }
373 }
374
375 /* Note, this will call r128ChooseTextureFormat */
376 _mesa_store_teximage2d(ctx, target, level, internalFormat,
377 width, height, border, format, type, pixels,
378 &ctx->Unpack, texObj, texImage);
379
380 t->dirty_images[0] |= (1 << level);
381 }
382
383
384 static void r128TexSubImage2D( GLcontext *ctx,
385 GLenum target,
386 GLint level,
387 GLint xoffset, GLint yoffset,
388 GLsizei width, GLsizei height,
389 GLenum format, GLenum type,
390 const GLvoid *pixels,
391 const struct gl_pixelstore_attrib *packing,
392 struct gl_texture_object *texObj,
393 struct gl_texture_image *texImage )
394 {
395 driTextureObject * t = (driTextureObject *) texObj->DriverData;
396
397 assert( t ); /* this _should_ be true */
398 if ( t ) {
399 driSwapOutTextureObject( t );
400 }
401 else {
402 t = (driTextureObject *) r128AllocTexObj(texObj);
403 if (!t) {
404 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
405 return;
406 }
407 }
408
409 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
410 height, format, type, pixels, packing, texObj,
411 texImage);
412 t->dirty_images[0] |= (1 << level);
413 }
414
415
416 static void r128TexEnv( GLcontext *ctx, GLenum target,
417 GLenum pname, const GLfloat *param )
418 {
419 r128ContextPtr rmesa = R128_CONTEXT(ctx);
420 struct gl_texture_unit *texUnit;
421 GLubyte c[4];
422
423 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
424 fprintf( stderr, "%s( %s )\n",
425 __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
426 }
427
428 switch ( pname ) {
429 case GL_TEXTURE_ENV_MODE:
430 FLUSH_BATCH( rmesa );
431 rmesa->new_state |= R128_NEW_ALPHA;
432 break;
433
434 case GL_TEXTURE_ENV_COLOR:
435 texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
436 CLAMPED_FLOAT_TO_UBYTE( c[0], texUnit->EnvColor[0] );
437 CLAMPED_FLOAT_TO_UBYTE( c[1], texUnit->EnvColor[1] );
438 CLAMPED_FLOAT_TO_UBYTE( c[2], texUnit->EnvColor[2] );
439 CLAMPED_FLOAT_TO_UBYTE( c[3], texUnit->EnvColor[3] );
440 rmesa->env_color = r128PackColor( 4, c[0], c[1], c[2], c[3] );
441 if ( rmesa->setup.constant_color_c != rmesa->env_color ) {
442 FLUSH_BATCH( rmesa );
443 rmesa->setup.constant_color_c = rmesa->env_color;
444
445 /* More complex multitexture/multipass fallbacks for GL_BLEND
446 * can be done later, but this allows a single pass GL_BLEND
447 * in some cases (ie. Performer town demo). This is only
448 * applicable to the regular Rage 128, as the Pro and M3 can
449 * handle true single-pass GL_BLEND texturing.
450 */
451 rmesa->blend_flags &= ~R128_BLEND_ENV_COLOR;
452 if ( R128_IS_PLAIN( rmesa ) &&
453 rmesa->env_color != 0x00000000 &&
454 rmesa->env_color != 0xff000000 &&
455 rmesa->env_color != 0x00ffffff &&
456 rmesa->env_color != 0xffffffff ) {
457 rmesa->blend_flags |= R128_BLEND_ENV_COLOR;
458 }
459 }
460 break;
461
462 case GL_TEXTURE_LOD_BIAS:
463 {
464 uint32_t t = rmesa->setup.tex_cntl_c;
465 GLint bias;
466 uint32_t b;
467
468 /* GTH: This isn't exactly correct, but gives good results up to a
469 * certain point. It is better than completely ignoring the LOD
470 * bias. Unfortunately there isn't much range in the bias, the
471 * spec mentions strides that vary between 0.5 and 2.0 but these
472 * numbers don't seem to relate the the GL LOD bias value at all.
473 */
474 if ( param[0] >= 1.0 ) {
475 bias = -128;
476 } else if ( param[0] >= 0.5 ) {
477 bias = -64;
478 } else if ( param[0] >= 0.25 ) {
479 bias = 0;
480 } else if ( param[0] >= 0.0 ) {
481 bias = 63;
482 } else {
483 bias = 127;
484 }
485
486 b = (uint32_t)bias & 0xff;
487 t &= ~R128_LOD_BIAS_MASK;
488 t |= (b << R128_LOD_BIAS_SHIFT);
489
490 if ( rmesa->setup.tex_cntl_c != t ) {
491 FLUSH_BATCH( rmesa );
492 rmesa->setup.tex_cntl_c = t;
493 rmesa->dirty |= R128_UPLOAD_CONTEXT;
494 }
495 }
496 break;
497
498 default:
499 return;
500 }
501 }
502
503
504 static void r128TexParameter( GLcontext *ctx, GLenum target,
505 struct gl_texture_object *tObj,
506 GLenum pname, const GLfloat *params )
507 {
508 r128ContextPtr rmesa = R128_CONTEXT(ctx);
509 r128TexObjPtr t = (r128TexObjPtr)tObj->DriverData;
510
511 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
512 fprintf( stderr, "%s( %s )\n",
513 __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
514 }
515
516 if ( ( target != GL_TEXTURE_2D ) && ( target != GL_TEXTURE_1D ) )
517 return;
518
519 switch ( pname ) {
520 case GL_TEXTURE_MIN_FILTER:
521 case GL_TEXTURE_MAG_FILTER:
522 if ( t->base.bound ) FLUSH_BATCH( rmesa );
523 r128SetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
524 break;
525
526 case GL_TEXTURE_WRAP_S:
527 case GL_TEXTURE_WRAP_T:
528 if ( t->base.bound ) FLUSH_BATCH( rmesa );
529 r128SetTexWrap( t, tObj->WrapS, tObj->WrapT );
530 break;
531
532 case GL_TEXTURE_BORDER_COLOR:
533 if ( t->base.bound ) FLUSH_BATCH( rmesa );
534 r128SetTexBorderColor( t, tObj->_BorderChan );
535 break;
536
537 case GL_TEXTURE_BASE_LEVEL:
538 case GL_TEXTURE_MAX_LEVEL:
539 case GL_TEXTURE_MIN_LOD:
540 case GL_TEXTURE_MAX_LOD:
541 /* This isn't the most efficient solution but there doesn't appear to
542 * be a nice alternative for R128. Since there's no LOD clamping,
543 * we just have to rely on loading the right subset of mipmap levels
544 * to simulate a clamped LOD.
545 */
546 if ( t->base.bound ) FLUSH_BATCH( rmesa );
547 driSwapOutTextureObject( (driTextureObject *) t );
548 break;
549
550 default:
551 return;
552 }
553 }
554
555 static void r128BindTexture( GLcontext *ctx, GLenum target,
556 struct gl_texture_object *tObj )
557 {
558 if ( R128_DEBUG & DEBUG_VERBOSE_API ) {
559 fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, (void *) tObj,
560 ctx->Texture.CurrentUnit );
561 }
562
563 assert( (target != GL_TEXTURE_2D && target != GL_TEXTURE_1D) ||
564 (tObj->DriverData != NULL) );
565 }
566
567
568 static void r128DeleteTexture( GLcontext *ctx,
569 struct gl_texture_object *tObj )
570 {
571 r128ContextPtr rmesa = R128_CONTEXT(ctx);
572 driTextureObject * t = (driTextureObject *) tObj->DriverData;
573
574 if ( t ) {
575 if ( t->bound && rmesa ) {
576 FLUSH_BATCH( rmesa );
577 }
578
579 driDestroyTextureObject( t );
580 }
581 /* Free mipmap images and the texture object itself */
582 _mesa_delete_texture_object(ctx, tObj);
583 }
584
585 /**
586 * Allocate a new texture object.
587 * Called via ctx->Driver.NewTextureObject.
588 * Note: we could use containment here to 'derive' the driver-specific
589 * texture object from the core mesa gl_texture_object. Not done at this time.
590 */
591 static struct gl_texture_object *
592 r128NewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
593 {
594 struct gl_texture_object *obj;
595 obj = _mesa_new_texture_object(ctx, name, target);
596 r128AllocTexObj( obj );
597 return obj;
598 }
599
600 void r128InitTextureFuncs( struct dd_function_table *functions )
601 {
602 functions->TexEnv = r128TexEnv;
603 functions->ChooseTextureFormat = r128ChooseTextureFormat;
604 functions->TexImage1D = r128TexImage1D;
605 functions->TexSubImage1D = r128TexSubImage1D;
606 functions->TexImage2D = r128TexImage2D;
607 functions->TexSubImage2D = r128TexSubImage2D;
608 functions->TexParameter = r128TexParameter;
609 functions->BindTexture = r128BindTexture;
610 functions->NewTextureObject = r128NewTextureObject;
611 functions->DeleteTexture = r128DeleteTexture;
612 functions->IsTextureResident = driIsTextureResident;
613
614 driInitTextureFormats();
615 }
616