patch to import Jon Smirl's work from Bitkeeper
[mesa.git] / src / mesa / drivers / dri / mga / mgatex.c
1 /*
2 * Copyright 2000-2001 VA Linux Systems, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 */
27 /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatex.c,v 1.14 2002/10/30 12:51:36 alanh Exp $ */
28
29 #include "glheader.h"
30 #include "mm.h"
31 #include "mgacontext.h"
32 #include "mgatex.h"
33 #include "mgaregs.h"
34 #include "mgatris.h"
35 #include "mgaioctl.h"
36
37 #include "colormac.h"
38 #include "context.h"
39 #include "enums.h"
40 #include "simple_list.h"
41 #include "imports.h"
42 #include "macros.h"
43 #include "texformat.h"
44 #include "texstore.h"
45 #include "teximage.h"
46
47 #include "swrast/swrast.h"
48
49 /**
50 * Set the texture wrap modes.
51 * Currently \c GL_REPEAT, \c GL_CLAMP and \c GL_CLAMP_TO_EDGE are supported.
52 *
53 * \param t Texture object whose wrap modes are to be set
54 * \param swrap Wrap mode for the \a s texture coordinate
55 * \param twrap Wrap mode for the \a t texture coordinate
56 */
57
58 static void
59 mgaSetTexWrapping( mgaTextureObjectPtr t, GLenum swrap, GLenum twrap )
60 {
61 GLboolean is_clamp = GL_FALSE;
62 GLboolean is_clamp_to_edge = GL_FALSE;
63
64 t->setup.texctl &= (TMC_clampu_MASK & TMC_clampv_MASK);
65 t->setup.texctl2 &= (TMC_borderen_MASK);
66
67 switch( swrap ) {
68 case GL_REPEAT:
69 break;
70 case GL_CLAMP:
71 t->setup.texctl |= TMC_clampu_enable;
72 is_clamp = GL_TRUE;
73 break;
74 case GL_CLAMP_TO_EDGE:
75 t->setup.texctl |= TMC_clampu_enable;
76 is_clamp_to_edge = GL_TRUE;
77 break;
78 default:
79 _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
80 }
81
82 switch( twrap ) {
83 case GL_REPEAT:
84 break;
85 case GL_CLAMP:
86 t->setup.texctl |= TMC_clampv_enable;
87 is_clamp = GL_TRUE;
88 break;
89 case GL_CLAMP_TO_EDGE:
90 t->setup.texctl |= TMC_clampv_enable;
91 is_clamp_to_edge = GL_TRUE;
92 break;
93 default:
94 _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
95 }
96
97 if ( is_clamp ) {
98 t->setup.texctl2 |= TMC_borderen_enable;
99 }
100
101 t->border_fallback = (is_clamp && is_clamp_to_edge);
102 }
103
104
105 /**
106 * Set the texture magnification and minification modes.
107 *
108 * \param t Texture whose filter modes are to be set
109 * \param minf Texture minification mode
110 * \param magf Texture magnification mode
111 */
112
113 static void
114 mgaSetTexFilter( mgaTextureObjectPtr t, GLenum minf, GLenum magf )
115 {
116 GLuint val = 0;
117
118 switch (minf) {
119 case GL_NEAREST: val = TF_minfilter_nrst; break;
120 case GL_LINEAR: val = TF_minfilter_bilin; break;
121 case GL_NEAREST_MIPMAP_NEAREST: val = TF_minfilter_mm1s; break;
122 case GL_LINEAR_MIPMAP_NEAREST: val = TF_minfilter_mm4s; break;
123 case GL_NEAREST_MIPMAP_LINEAR: val = TF_minfilter_mm2s; break;
124 case GL_LINEAR_MIPMAP_LINEAR: val = TF_minfilter_mm8s; break;
125 default: val = TF_minfilter_nrst; break;
126 }
127
128 switch (magf) {
129 case GL_NEAREST: val |= TF_magfilter_nrst; break;
130 case GL_LINEAR: val |= TF_magfilter_bilin; break;
131 default: val |= TF_magfilter_nrst; break;
132 }
133
134 /* See OpenGL 1.2 specification */
135 if (magf == GL_LINEAR && (minf == GL_NEAREST_MIPMAP_NEAREST ||
136 minf == GL_NEAREST_MIPMAP_LINEAR)) {
137 val |= (0x20 << TF_fthres_SHIFT); /* c = 0.5 */
138 } else {
139 val |= (0x10 << TF_fthres_SHIFT); /* c = 0 */
140 }
141
142
143 /* Mask off the bits for the fields we are setting. Remember, the MGA mask
144 * defines have 0s for the bits in the named fields. This is the opposite
145 * of most of the other drivers.
146 */
147
148 t->setup.texfilter &= (TF_minfilter_MASK &
149 TF_magfilter_MASK &
150 TF_fthres_MASK);
151 t->setup.texfilter |= val;
152 }
153
154 static void mgaSetTexBorderColor(mgaTextureObjectPtr t, GLubyte color[4])
155 {
156 t->setup.texbordercol = PACK_COLOR_8888(color[3], color[0],
157 color[1], color[2] );
158 }
159
160
161 static const struct gl_texture_format *
162 mgaChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
163 GLenum format, GLenum type )
164 {
165 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
166 const GLboolean do32bpt = mmesa->default32BitTextures;
167
168 switch ( internalFormat ) {
169 case 4:
170 case GL_RGBA:
171 case GL_COMPRESSED_RGBA:
172 if ( format == GL_BGRA ) {
173 if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) {
174 return &_mesa_texformat_argb8888;
175 }
176 else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) {
177 return &_mesa_texformat_argb4444;
178 }
179 else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) {
180 return &_mesa_texformat_argb1555;
181 }
182 }
183 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
184
185 case 3:
186 case GL_RGB:
187 case GL_COMPRESSED_RGB:
188 if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) {
189 return &_mesa_texformat_rgb565;
190 }
191 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
192
193 case GL_RGBA8:
194 case GL_RGB10_A2:
195 case GL_RGBA12:
196 case GL_RGBA16:
197 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
198
199 case GL_RGBA4:
200 case GL_RGBA2:
201 return &_mesa_texformat_argb4444;
202
203 case GL_RGB5_A1:
204 return &_mesa_texformat_argb1555;
205
206 case GL_RGB8:
207 case GL_RGB10:
208 case GL_RGB12:
209 case GL_RGB16:
210 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
211
212 case GL_RGB5:
213 case GL_RGB4:
214 case GL_R3_G3_B2:
215 return &_mesa_texformat_rgb565;
216
217 case GL_ALPHA:
218 case GL_ALPHA4:
219 case GL_ALPHA8:
220 case GL_ALPHA12:
221 case GL_ALPHA16:
222 case GL_COMPRESSED_ALPHA:
223 /* FIXME: This will report incorrect component sizes... */
224 return &_mesa_texformat_argb4444;
225
226 case 1:
227 case GL_LUMINANCE:
228 case GL_LUMINANCE4:
229 case GL_LUMINANCE8:
230 case GL_LUMINANCE12:
231 case GL_LUMINANCE16:
232 case GL_COMPRESSED_LUMINANCE:
233 /* FIXME: This will report incorrect component sizes... */
234 return &_mesa_texformat_rgb565;
235
236 case 2:
237 case GL_LUMINANCE_ALPHA:
238 case GL_LUMINANCE4_ALPHA4:
239 case GL_LUMINANCE6_ALPHA2:
240 case GL_LUMINANCE8_ALPHA8:
241 case GL_LUMINANCE12_ALPHA4:
242 case GL_LUMINANCE12_ALPHA12:
243 case GL_LUMINANCE16_ALPHA16:
244 case GL_COMPRESSED_LUMINANCE_ALPHA:
245 /* FIXME: This will report incorrect component sizes... */
246 return &_mesa_texformat_argb4444;
247
248 case GL_INTENSITY:
249 case GL_INTENSITY4:
250 case GL_INTENSITY8:
251 case GL_INTENSITY12:
252 case GL_INTENSITY16:
253 case GL_COMPRESSED_INTENSITY:
254 /* FIXME: This will report incorrect component sizes... */
255 return &_mesa_texformat_argb4444;
256
257 case GL_YCBCR_MESA:
258 if (MGA_IS_G400(mmesa) &&
259 (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
260 type == GL_UNSIGNED_BYTE))
261 return &_mesa_texformat_ycbcr;
262 else
263 return &_mesa_texformat_ycbcr_rev;
264
265 case GL_COLOR_INDEX:
266 case GL_COLOR_INDEX1_EXT:
267 case GL_COLOR_INDEX2_EXT:
268 case GL_COLOR_INDEX4_EXT:
269 case GL_COLOR_INDEX8_EXT:
270 case GL_COLOR_INDEX12_EXT:
271 case GL_COLOR_INDEX16_EXT:
272 return &_mesa_texformat_ci8;
273
274 default:
275 _mesa_problem( ctx, "unexpected texture format in %s", __FUNCTION__ );
276 return NULL;
277 }
278
279 return NULL; /* never get here */
280 }
281
282
283
284
285 /**
286 * Allocate space for and load the mesa images into the texture memory block.
287 * This will happen before drawing with a new texture, or drawing with a
288 * texture after it was swapped out or teximaged again.
289 */
290
291 static mgaTextureObjectPtr
292 mgaAllocTexObj( struct gl_texture_object *tObj )
293 {
294 mgaTextureObjectPtr t;
295
296
297 t = CALLOC( sizeof( *t ) );
298 tObj->DriverData = t;
299 if ( t != NULL ) {
300 /* Initialize non-image-dependent parts of the state:
301 */
302 t->base.tObj = tObj;
303
304 t->setup.texctl = TMC_takey_1 | TMC_tamask_0;
305 t->setup.texctl2 = TMC_ckstransdis_enable;
306 t->setup.texfilter = (TF_minfilter_nrst
307 | TF_magfilter_nrst
308 | TF_filteralpha_enable
309 | TF_uvoffset_OGL);
310
311 t->border_fallback = GL_FALSE;
312
313 make_empty_list( & t->base );
314
315 mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT );
316 mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
317 mgaSetTexBorderColor( t, tObj->_BorderChan );
318 }
319
320 return( t );
321 }
322
323
324 static void mgaDDTexEnv( GLcontext *ctx, GLenum target,
325 GLenum pname, const GLfloat *param )
326 {
327 GLuint unit = ctx->Texture.CurrentUnit;
328 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
329 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
330
331
332 switch( pname ) {
333 case GL_TEXTURE_ENV_COLOR: {
334 GLubyte c[4];
335 GLuint envColor;
336
337 UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
338 envColor = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3] );
339 mmesa->envcolor = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
340
341 if (mmesa->setup.fcol != envColor) {
342 FLUSH_BATCH(mmesa);
343 mmesa->setup.fcol = envColor;
344 mmesa->dirty |= MGA_UPLOAD_CONTEXT;
345
346 mmesa->blend_flags &= ~MGA_BLEND_ENV_COLOR;
347
348 /* Actually just require all four components to be
349 * equal. This permits a single-pass GL_BLEND.
350 *
351 * More complex multitexture/multipass fallbacks
352 * for blend can be done later.
353 */
354 if (mmesa->envcolor != 0x0 && mmesa->envcolor != 0xffffffff)
355 mmesa->blend_flags |= MGA_BLEND_ENV_COLOR;
356 }
357 break;
358 }
359 }
360 }
361
362
363 static void mgaTexImage2D( GLcontext *ctx, GLenum target, GLint level,
364 GLint internalFormat,
365 GLint width, GLint height, GLint border,
366 GLenum format, GLenum type, const GLvoid *pixels,
367 const struct gl_pixelstore_attrib *packing,
368 struct gl_texture_object *texObj,
369 struct gl_texture_image *texImage )
370 {
371 driTextureObject * t = (driTextureObject *) texObj->DriverData;
372
373
374 if ( t != NULL ) {
375 driSwapOutTextureObject( t );
376 }
377 else {
378 t = (driTextureObject *) mgaAllocTexObj( texObj );
379 if ( t == NULL ) {
380 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
381 return;
382 }
383 }
384
385 _mesa_store_teximage2d( ctx, target, level, internalFormat,
386 width, height, border, format, type,
387 pixels, packing, texObj, texImage );
388 level -= t->firstLevel;
389 if (level >= 0)
390 t->dirty_images[0] |= (1UL << level);
391 }
392
393 static void mgaTexSubImage2D( GLcontext *ctx,
394 GLenum target,
395 GLint level,
396 GLint xoffset, GLint yoffset,
397 GLsizei width, GLsizei height,
398 GLenum format, GLenum type,
399 const GLvoid *pixels,
400 const struct gl_pixelstore_attrib *packing,
401 struct gl_texture_object *texObj,
402 struct gl_texture_image *texImage )
403 {
404 driTextureObject * t = (driTextureObject *) texObj->DriverData;
405
406
407 assert( t != NULL ); /* this _should_ be true */
408 if ( t != NULL ) {
409 driSwapOutTextureObject( t );
410 }
411 else {
412 t = (driTextureObject *) mgaAllocTexObj( texObj );
413 if ( t == NULL ) {
414 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
415 return;
416 }
417 }
418
419 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
420 height, format, type, pixels, packing, texObj,
421 texImage);
422 level -= t->firstLevel;
423 if (level >= 0)
424 t->dirty_images[0] |= (1UL << level);
425 }
426
427
428 /**
429 * Changes variables and flags for a state update, which will happen at the
430 * next UpdateTextureState
431 */
432
433 static void
434 mgaDDTexParameter( GLcontext *ctx, GLenum target,
435 struct gl_texture_object *tObj,
436 GLenum pname, const GLfloat *params )
437 {
438 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
439 mgaTextureObjectPtr t;
440
441 t = (mgaTextureObjectPtr) tObj->DriverData;
442
443 /* If we don't have a hardware texture, it will be automatically
444 * created with current state before it is used, so we don't have
445 * to do anything now
446 */
447
448 if ( (t == NULL)
449 || (target != GL_TEXTURE_2D) ) {
450 return;
451 }
452
453 switch (pname) {
454 case GL_TEXTURE_MIN_FILTER:
455 driSwapOutTextureObject( (driTextureObject *) t );
456 /* FALLTHROUGH */
457 case GL_TEXTURE_MAG_FILTER:
458 FLUSH_BATCH(mmesa);
459 mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
460 break;
461
462 case GL_TEXTURE_WRAP_S:
463 case GL_TEXTURE_WRAP_T:
464 FLUSH_BATCH(mmesa);
465 mgaSetTexWrapping(t,tObj->WrapS,tObj->WrapT);
466 break;
467
468 case GL_TEXTURE_BORDER_COLOR:
469 FLUSH_BATCH(mmesa);
470 mgaSetTexBorderColor(t, tObj->_BorderChan);
471 break;
472
473 case GL_TEXTURE_BASE_LEVEL:
474 case GL_TEXTURE_MAX_LEVEL:
475 case GL_TEXTURE_MIN_LOD:
476 case GL_TEXTURE_MAX_LOD:
477 /* This isn't the most efficient solution but there doesn't appear to
478 * be a nice alternative. Since there's no LOD clamping,
479 * we just have to rely on loading the right subset of mipmap levels
480 * to simulate a clamped LOD.
481 */
482 driSwapOutTextureObject( (driTextureObject *) t );
483 break;
484
485 default:
486 return;
487 }
488 }
489
490
491 static void
492 mgaDDBindTexture( GLcontext *ctx, GLenum target,
493 struct gl_texture_object *tObj )
494 {
495 if ( target == GL_TEXTURE_2D ) {
496 if ( tObj->DriverData == NULL ) {
497 mgaAllocTexObj( tObj );
498 }
499 }
500 }
501
502
503 static void
504 mgaDDDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
505 {
506 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
507 driTextureObject * t = (driTextureObject *) tObj->DriverData;
508
509 if ( t ) {
510 if ( mmesa ) {
511 FLUSH_BATCH( mmesa );
512 }
513
514 driDestroyTextureObject( t );
515 }
516 }
517
518
519 void
520 mgaDDInitTextureFuncs( GLcontext *ctx )
521 {
522 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
523
524
525 ctx->Driver.ChooseTextureFormat = mgaChooseTextureFormat;
526 ctx->Driver.TexImage1D = _mesa_store_teximage1d;
527 ctx->Driver.TexImage2D = mgaTexImage2D;
528 ctx->Driver.TexImage3D = _mesa_store_teximage3d;
529 ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d;
530 ctx->Driver.TexSubImage2D = mgaTexSubImage2D;
531 ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d;
532 ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d;
533 ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d;
534 ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d;
535 ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d;
536 ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d;
537 ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage;
538
539 ctx->Driver.BindTexture = mgaDDBindTexture;
540 ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */
541 ctx->Driver.DeleteTexture = mgaDDDeleteTexture;
542 ctx->Driver.IsTextureResident = driIsTextureResident;
543 ctx->Driver.PrioritizeTexture = NULL;
544 ctx->Driver.ActiveTexture = NULL;
545 ctx->Driver.UpdateTexturePalette = NULL;
546
547 ctx->Driver.TexEnv = mgaDDTexEnv;
548 ctx->Driver.TexParameter = mgaDDTexParameter;
549
550 driInitTextureObjects( ctx, & mmesa->swapped, DRI_TEXMGR_DO_TEXTURE_2D );
551 }