8caa1f8580f2f801e7924537b5a97835df9b2f3a
[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 #include "texobj.h"
47
48 #include "swrast/swrast.h"
49
50 #include "xmlpool.h"
51
52 /**
53 * Set the texture wrap modes.
54 * Currently \c GL_REPEAT, \c GL_CLAMP and \c GL_CLAMP_TO_EDGE are supported.
55 *
56 * \param t Texture object whose wrap modes are to be set
57 * \param swrap Wrap mode for the \a s texture coordinate
58 * \param twrap Wrap mode for the \a t texture coordinate
59 */
60
61 static void
62 mgaSetTexWrapping( mgaTextureObjectPtr t, GLenum swrap, GLenum twrap )
63 {
64 GLboolean is_clamp = GL_FALSE;
65 GLboolean is_clamp_to_edge = GL_FALSE;
66
67 t->setup.texctl &= (TMC_clampu_MASK & TMC_clampv_MASK);
68 t->setup.texctl2 &= (TMC_borderen_MASK);
69
70 switch( swrap ) {
71 case GL_REPEAT:
72 break;
73 case GL_CLAMP:
74 t->setup.texctl |= TMC_clampu_enable;
75 is_clamp = GL_TRUE;
76 break;
77 case GL_CLAMP_TO_EDGE:
78 t->setup.texctl |= TMC_clampu_enable;
79 is_clamp_to_edge = GL_TRUE;
80 break;
81 default:
82 _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
83 }
84
85 switch( twrap ) {
86 case GL_REPEAT:
87 break;
88 case GL_CLAMP:
89 t->setup.texctl |= TMC_clampv_enable;
90 is_clamp = GL_TRUE;
91 break;
92 case GL_CLAMP_TO_EDGE:
93 t->setup.texctl |= TMC_clampv_enable;
94 is_clamp_to_edge = GL_TRUE;
95 break;
96 default:
97 _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
98 }
99
100 if ( is_clamp ) {
101 t->setup.texctl2 |= TMC_borderen_enable;
102 }
103
104 t->border_fallback = (is_clamp && is_clamp_to_edge);
105 }
106
107
108 /**
109 * Set the texture magnification and minification modes.
110 *
111 * \param t Texture whose filter modes are to be set
112 * \param minf Texture minification mode
113 * \param magf Texture magnification mode
114 */
115
116 static void
117 mgaSetTexFilter( mgaTextureObjectPtr t, GLenum minf, GLenum magf )
118 {
119 GLuint val = 0;
120
121 switch (minf) {
122 case GL_NEAREST: val = TF_minfilter_nrst; break;
123 case GL_LINEAR: val = TF_minfilter_bilin; break;
124 case GL_NEAREST_MIPMAP_NEAREST: val = TF_minfilter_mm1s; break;
125 case GL_LINEAR_MIPMAP_NEAREST: val = TF_minfilter_mm4s; break;
126 case GL_NEAREST_MIPMAP_LINEAR: val = TF_minfilter_mm2s; break;
127 case GL_LINEAR_MIPMAP_LINEAR: val = TF_minfilter_mm8s; break;
128 default: val = TF_minfilter_nrst; break;
129 }
130
131 switch (magf) {
132 case GL_NEAREST: val |= TF_magfilter_nrst; break;
133 case GL_LINEAR: val |= TF_magfilter_bilin; break;
134 default: val |= TF_magfilter_nrst; break;
135 }
136
137 /* See OpenGL 1.2 specification */
138 if (magf == GL_LINEAR && (minf == GL_NEAREST_MIPMAP_NEAREST ||
139 minf == GL_NEAREST_MIPMAP_LINEAR)) {
140 val |= MGA_FIELD( TF_fthres, 0x20 ); /* c = 0.5 */
141 } else {
142 val |= MGA_FIELD( TF_fthres, 0x10 ); /* c = 0 */
143 }
144
145
146 /* Mask off the bits for the fields we are setting. Remember, the MGA mask
147 * defines have 0s for the bits in the named fields. This is the opposite
148 * of most of the other drivers.
149 */
150
151 t->setup.texfilter &= (TF_minfilter_MASK &
152 TF_magfilter_MASK &
153 TF_fthres_MASK);
154 t->setup.texfilter |= val;
155 }
156
157 static void mgaSetTexBorderColor(mgaTextureObjectPtr t, GLubyte color[4])
158 {
159 t->setup.texbordercol = PACK_COLOR_8888(color[3], color[0],
160 color[1], color[2] );
161 }
162
163
164 static const struct gl_texture_format *
165 mgaChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
166 GLenum format, GLenum type )
167 {
168 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
169 const GLboolean do32bpt =
170 ( mmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
171 const GLboolean force16bpt =
172 ( mmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
173 (void) format;
174
175 switch ( internalFormat ) {
176 case 4:
177 case GL_RGBA:
178 case GL_COMPRESSED_RGBA:
179 switch ( type ) {
180 case GL_UNSIGNED_INT_10_10_10_2:
181 case GL_UNSIGNED_INT_2_10_10_10_REV:
182 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
183 case GL_UNSIGNED_SHORT_4_4_4_4:
184 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
185 return &_mesa_texformat_argb4444;
186 case GL_UNSIGNED_SHORT_5_5_5_1:
187 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
188 return &_mesa_texformat_argb1555;
189 default:
190 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
191 }
192
193 case 3:
194 case GL_RGB:
195 case GL_COMPRESSED_RGB:
196 switch ( type ) {
197 case GL_UNSIGNED_SHORT_4_4_4_4:
198 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
199 return &_mesa_texformat_argb4444;
200 case GL_UNSIGNED_SHORT_5_5_5_1:
201 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
202 return &_mesa_texformat_argb1555;
203 case GL_UNSIGNED_SHORT_5_6_5:
204 case GL_UNSIGNED_SHORT_5_6_5_REV:
205 return &_mesa_texformat_rgb565;
206 default:
207 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
208 }
209
210 case GL_RGBA8:
211 case GL_RGB10_A2:
212 case GL_RGBA12:
213 case GL_RGBA16:
214 return !force16bpt ?
215 &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
216
217 case GL_RGBA4:
218 case GL_RGBA2:
219 return &_mesa_texformat_argb4444;
220
221 case GL_RGB5_A1:
222 return &_mesa_texformat_argb1555;
223
224 case GL_RGB8:
225 case GL_RGB10:
226 case GL_RGB12:
227 case GL_RGB16:
228 return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
229
230 case GL_RGB5:
231 case GL_RGB4:
232 case GL_R3_G3_B2:
233 return &_mesa_texformat_rgb565;
234
235 case GL_ALPHA:
236 case GL_ALPHA4:
237 case GL_ALPHA8:
238 case GL_ALPHA12:
239 case GL_ALPHA16:
240 case GL_COMPRESSED_ALPHA:
241 /* FIXME: This will report incorrect component sizes... */
242 return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444;
243
244 case 1:
245 case GL_LUMINANCE:
246 case GL_LUMINANCE4:
247 case GL_LUMINANCE8:
248 case GL_LUMINANCE12:
249 case GL_LUMINANCE16:
250 case GL_COMPRESSED_LUMINANCE:
251 /* FIXME: This will report incorrect component sizes... */
252 return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_rgb565;
253
254 case 2:
255 case GL_LUMINANCE_ALPHA:
256 case GL_LUMINANCE4_ALPHA4:
257 case GL_LUMINANCE6_ALPHA2:
258 case GL_LUMINANCE8_ALPHA8:
259 case GL_LUMINANCE12_ALPHA4:
260 case GL_LUMINANCE12_ALPHA12:
261 case GL_LUMINANCE16_ALPHA16:
262 case GL_COMPRESSED_LUMINANCE_ALPHA:
263 /* FIXME: This will report incorrect component sizes... */
264 return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444;
265
266 case GL_INTENSITY:
267 case GL_INTENSITY4:
268 case GL_INTENSITY8:
269 case GL_INTENSITY12:
270 case GL_INTENSITY16:
271 case GL_COMPRESSED_INTENSITY:
272 /* FIXME: This will report incorrect component sizes... */
273 return MGA_IS_G400(mmesa) ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444;
274
275 case GL_YCBCR_MESA:
276 if (MGA_IS_G400(mmesa) &&
277 (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
278 type == GL_UNSIGNED_BYTE))
279 return &_mesa_texformat_ycbcr;
280 else
281 return &_mesa_texformat_ycbcr_rev;
282
283 case GL_COLOR_INDEX:
284 case GL_COLOR_INDEX1_EXT:
285 case GL_COLOR_INDEX2_EXT:
286 case GL_COLOR_INDEX4_EXT:
287 case GL_COLOR_INDEX8_EXT:
288 case GL_COLOR_INDEX12_EXT:
289 case GL_COLOR_INDEX16_EXT:
290 return &_mesa_texformat_ci8;
291
292 default:
293 _mesa_problem( ctx, "unexpected texture format in %s", __FUNCTION__ );
294 return NULL;
295 }
296
297 return NULL; /* never get here */
298 }
299
300
301
302
303 /**
304 * Allocate space for and load the mesa images into the texture memory block.
305 * This will happen before drawing with a new texture, or drawing with a
306 * texture after it was swapped out or teximaged again.
307 */
308
309 static mgaTextureObjectPtr
310 mgaAllocTexObj( struct gl_texture_object *tObj )
311 {
312 mgaTextureObjectPtr t;
313
314
315 t = CALLOC( sizeof( *t ) );
316 tObj->DriverData = t;
317 if ( t != NULL ) {
318 /* Initialize non-image-dependent parts of the state:
319 */
320 t->base.tObj = tObj;
321
322 t->setup.texctl = TMC_takey_1 | TMC_tamask_0;
323 t->setup.texctl2 = TMC_ckstransdis_enable;
324 t->setup.texfilter = TF_filteralpha_enable | TF_uvoffset_OGL;
325
326 t->border_fallback = GL_FALSE;
327 t->texenv_fallback = GL_FALSE;
328
329 make_empty_list( & t->base );
330
331 mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT );
332 mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
333 mgaSetTexBorderColor( t, tObj->_BorderChan );
334 }
335
336 return( t );
337 }
338
339
340 static void mgaTexEnv( GLcontext *ctx, GLenum target,
341 GLenum pname, const GLfloat *param )
342 {
343 GLuint unit = ctx->Texture.CurrentUnit;
344 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
345 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
346
347 switch( pname ) {
348 case GL_TEXTURE_ENV_COLOR: {
349 GLubyte c[4];
350
351 UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
352 mmesa->envcolor[unit] = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
353 break;
354 }
355 }
356 }
357
358
359 static void mgaTexImage2D( GLcontext *ctx, GLenum target, GLint level,
360 GLint internalFormat,
361 GLint width, GLint height, GLint border,
362 GLenum format, GLenum type, const GLvoid *pixels,
363 const struct gl_pixelstore_attrib *packing,
364 struct gl_texture_object *texObj,
365 struct gl_texture_image *texImage )
366 {
367 driTextureObject * t = (driTextureObject *) texObj->DriverData;
368
369 if ( t != NULL ) {
370 driSwapOutTextureObject( t );
371 }
372 else {
373 t = (driTextureObject *) mgaAllocTexObj( texObj );
374 if ( t == NULL ) {
375 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
376 return;
377 }
378 }
379
380 _mesa_store_teximage2d( ctx, target, level, internalFormat,
381 width, height, border, format, type,
382 pixels, packing, texObj, texImage );
383 level -= t->firstLevel;
384 if (level >= 0)
385 t->dirty_images[0] |= (1UL << level);
386 }
387
388 static void mgaTexSubImage2D( GLcontext *ctx,
389 GLenum target,
390 GLint level,
391 GLint xoffset, GLint yoffset,
392 GLsizei width, GLsizei height,
393 GLenum format, GLenum type,
394 const GLvoid *pixels,
395 const struct gl_pixelstore_attrib *packing,
396 struct gl_texture_object *texObj,
397 struct gl_texture_image *texImage )
398 {
399 driTextureObject * t = (driTextureObject *) texObj->DriverData;
400
401 assert( t ); /* this _should_ be true */
402 if ( t != NULL ) {
403 driSwapOutTextureObject( t );
404 }
405 else {
406 t = (driTextureObject *) mgaAllocTexObj( texObj );
407 if ( t == NULL ) {
408 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
409 return;
410 }
411 }
412
413 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
414 height, format, type, pixels, packing, texObj,
415 texImage);
416 level -= t->firstLevel;
417 if (level >= 0)
418 t->dirty_images[0] |= (1UL << level);
419 }
420
421
422 /**
423 * Changes variables and flags for a state update, which will happen at the
424 * next UpdateTextureState
425 */
426
427 static void
428 mgaTexParameter( GLcontext *ctx, GLenum target,
429 struct gl_texture_object *tObj,
430 GLenum pname, const GLfloat *params )
431 {
432 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
433 mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
434
435 /* If we don't have a hardware texture, it will be automatically
436 * created with current state before it is used, so we don't have
437 * to do anything now
438 */
439 if ( (t == NULL) ||
440 (target != GL_TEXTURE_2D &&
441 target != GL_TEXTURE_RECTANGLE_NV) ) {
442 return;
443 }
444
445 switch (pname) {
446 case GL_TEXTURE_MIN_FILTER:
447 driSwapOutTextureObject( (driTextureObject *) t );
448 /* FALLTHROUGH */
449 case GL_TEXTURE_MAG_FILTER:
450 FLUSH_BATCH(mmesa);
451 mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
452 break;
453
454 case GL_TEXTURE_WRAP_S:
455 case GL_TEXTURE_WRAP_T:
456 FLUSH_BATCH(mmesa);
457 mgaSetTexWrapping(t,tObj->WrapS,tObj->WrapT);
458 break;
459
460 case GL_TEXTURE_BORDER_COLOR:
461 FLUSH_BATCH(mmesa);
462 mgaSetTexBorderColor(t, tObj->_BorderChan);
463 break;
464
465 case GL_TEXTURE_BASE_LEVEL:
466 case GL_TEXTURE_MAX_LEVEL:
467 case GL_TEXTURE_MIN_LOD:
468 case GL_TEXTURE_MAX_LOD:
469 /* This isn't the most efficient solution but there doesn't appear to
470 * be a nice alternative. Since there's no LOD clamping,
471 * we just have to rely on loading the right subset of mipmap levels
472 * to simulate a clamped LOD.
473 */
474 driSwapOutTextureObject( (driTextureObject *) t );
475 break;
476
477 default:
478 return;
479 }
480 }
481
482
483 static void
484 mgaBindTexture( GLcontext *ctx, GLenum target,
485 struct gl_texture_object *tObj )
486 {
487 assert( (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_NV) ||
488 (tObj->DriverData != NULL) );
489 }
490
491
492 static void
493 mgaDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
494 {
495 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
496 driTextureObject * t = (driTextureObject *) tObj->DriverData;
497
498 if ( t ) {
499 if ( mmesa ) {
500 FLUSH_BATCH( mmesa );
501 }
502
503 driDestroyTextureObject( t );
504 }
505 }
506
507
508 /**
509 * Allocate a new texture object.
510 * Called via ctx->Driver.NewTextureObject.
511 * Note: this function will be called during context creation to
512 * allocate the default texture objects.
513 * Note: we could use containment here to 'derive' the driver-specific
514 * texture object from the core mesa gl_texture_object. Not done at this time.
515 */
516 static struct gl_texture_object *
517 mgaNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
518 {
519 struct gl_texture_object *obj;
520 obj = _mesa_new_texture_object(ctx, name, target);
521 mgaAllocTexObj( obj );
522 return obj;
523 }
524
525
526 void
527 mgaInitTextureFuncs( struct dd_function_table *functions )
528 {
529 functions->ChooseTextureFormat = mgaChooseTextureFormat;
530 functions->TexImage2D = mgaTexImage2D;
531 functions->TexSubImage2D = mgaTexSubImage2D;
532 functions->BindTexture = mgaBindTexture;
533 functions->NewTextureObject = mgaNewTextureObject;
534 functions->DeleteTexture = mgaDeleteTexture;
535 functions->IsTextureResident = driIsTextureResident;
536 functions->TexEnv = mgaTexEnv;
537 functions->TexParameter = mgaTexParameter;
538 }