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