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