33eb0be449662f804396518d1f9253068e8cd803
[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, const GLfloat color[4])
157 {
158 GLubyte c[4];
159 CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
160 CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
161 CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
162 CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
163 t->setup.texbordercol = PACK_COLOR_8888(c[3], c[0], c[1], c[2] );
164 }
165
166
167 static const struct gl_texture_format *
168 mgaChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
169 GLenum format, GLenum type )
170 {
171 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
172 const GLboolean do32bpt =
173 ( mmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
174 const GLboolean force16bpt =
175 ( mmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
176 (void) format;
177
178 switch ( internalFormat ) {
179 case 4:
180 case GL_RGBA:
181 case GL_COMPRESSED_RGBA:
182 switch ( type ) {
183 case GL_UNSIGNED_INT_10_10_10_2:
184 case GL_UNSIGNED_INT_2_10_10_10_REV:
185 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
186 case GL_UNSIGNED_SHORT_4_4_4_4:
187 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
188 return &_mesa_texformat_argb4444;
189 case GL_UNSIGNED_SHORT_5_5_5_1:
190 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
191 return &_mesa_texformat_argb1555;
192 default:
193 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
194 }
195
196 case 3:
197 case GL_RGB:
198 case GL_COMPRESSED_RGB:
199 switch ( type ) {
200 case GL_UNSIGNED_SHORT_4_4_4_4:
201 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
202 return &_mesa_texformat_argb4444;
203 case GL_UNSIGNED_SHORT_5_5_5_1:
204 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
205 return &_mesa_texformat_argb1555;
206 case GL_UNSIGNED_SHORT_5_6_5:
207 case GL_UNSIGNED_SHORT_5_6_5_REV:
208 return &_mesa_texformat_rgb565;
209 default:
210 return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
211 }
212
213 case GL_RGBA8:
214 case GL_RGB10_A2:
215 case GL_RGBA12:
216 case GL_RGBA16:
217 return !force16bpt ?
218 &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
219
220 case GL_RGBA4:
221 case GL_RGBA2:
222 return &_mesa_texformat_argb4444;
223
224 case GL_RGB5_A1:
225 return &_mesa_texformat_argb1555;
226
227 case GL_RGB8:
228 case GL_RGB10:
229 case GL_RGB12:
230 case GL_RGB16:
231 return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
232
233 case GL_RGB5:
234 case GL_RGB4:
235 case GL_R3_G3_B2:
236 return &_mesa_texformat_rgb565;
237
238 case GL_ALPHA:
239 case GL_ALPHA4:
240 case GL_ALPHA8:
241 case GL_ALPHA12:
242 case GL_ALPHA16:
243 case GL_COMPRESSED_ALPHA:
244 /* FIXME: This will report incorrect component sizes... */
245 return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444;
246
247 case 1:
248 case GL_LUMINANCE:
249 case GL_LUMINANCE4:
250 case GL_LUMINANCE8:
251 case GL_LUMINANCE12:
252 case GL_LUMINANCE16:
253 case GL_COMPRESSED_LUMINANCE:
254 /* FIXME: This will report incorrect component sizes... */
255 return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_rgb565;
256
257 case 2:
258 case GL_LUMINANCE_ALPHA:
259 case GL_LUMINANCE4_ALPHA4:
260 case GL_LUMINANCE6_ALPHA2:
261 case GL_LUMINANCE8_ALPHA8:
262 case GL_LUMINANCE12_ALPHA4:
263 case GL_LUMINANCE12_ALPHA12:
264 case GL_LUMINANCE16_ALPHA16:
265 case GL_COMPRESSED_LUMINANCE_ALPHA:
266 /* FIXME: This will report incorrect component sizes... */
267 return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444;
268
269 case GL_INTENSITY:
270 case GL_INTENSITY4:
271 case GL_INTENSITY8:
272 case GL_INTENSITY12:
273 case GL_INTENSITY16:
274 case GL_COMPRESSED_INTENSITY:
275 /* FIXME: This will report incorrect component sizes... */
276 return MGA_IS_G400(mmesa) ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444;
277
278 case GL_YCBCR_MESA:
279 if (MGA_IS_G400(mmesa) &&
280 (type == GL_UNSIGNED_SHORT_8_8_APPLE ||
281 type == GL_UNSIGNED_BYTE))
282 return &_mesa_texformat_ycbcr;
283 else
284 return &_mesa_texformat_ycbcr_rev;
285
286 case GL_COLOR_INDEX:
287 case GL_COLOR_INDEX1_EXT:
288 case GL_COLOR_INDEX2_EXT:
289 case GL_COLOR_INDEX4_EXT:
290 case GL_COLOR_INDEX8_EXT:
291 case GL_COLOR_INDEX12_EXT:
292 case GL_COLOR_INDEX16_EXT:
293 return &_mesa_texformat_ci8;
294
295 default:
296 _mesa_problem( ctx, "unexpected texture format in %s", __FUNCTION__ );
297 return NULL;
298 }
299
300 return NULL; /* never get here */
301 }
302
303
304
305
306 /**
307 * Allocate space for and load the mesa images into the texture memory block.
308 * This will happen before drawing with a new texture, or drawing with a
309 * texture after it was swapped out or teximaged again.
310 */
311
312 static mgaTextureObjectPtr
313 mgaAllocTexObj( struct gl_texture_object *tObj )
314 {
315 mgaTextureObjectPtr t;
316
317
318 t = CALLOC( sizeof( *t ) );
319 tObj->DriverData = t;
320 if ( t != NULL ) {
321 /* Initialize non-image-dependent parts of the state:
322 */
323 t->base.tObj = tObj;
324
325 t->setup.texctl = TMC_takey_1 | TMC_tamask_0;
326 t->setup.texctl2 = TMC_ckstransdis_enable;
327 t->setup.texfilter = TF_filteralpha_enable | TF_uvoffset_OGL;
328
329 t->border_fallback = GL_FALSE;
330 t->texenv_fallback = GL_FALSE;
331
332 make_empty_list( & t->base );
333
334 mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT );
335 mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
336 mgaSetTexBorderColor( t, tObj->BorderColor );
337 }
338
339 return( t );
340 }
341
342
343 static void mgaTexEnv( GLcontext *ctx, GLenum target,
344 GLenum pname, const GLfloat *param )
345 {
346 GLuint unit = ctx->Texture.CurrentUnit;
347 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
348 mgaContextPtr mmesa = MGA_CONTEXT(ctx);
349
350 switch( pname ) {
351 case GL_TEXTURE_ENV_COLOR: {
352 GLubyte c[4];
353
354 UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
355 mmesa->envcolor[unit] = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
356 break;
357 }
358 }
359 }
360
361
362 static void mgaTexImage2D( GLcontext *ctx, GLenum target, GLint level,
363 GLint internalFormat,
364 GLint width, GLint height, GLint border,
365 GLenum format, GLenum type, const GLvoid *pixels,
366 const struct gl_pixelstore_attrib *packing,
367 struct gl_texture_object *texObj,
368 struct gl_texture_image *texImage )
369 {
370 driTextureObject * t = (driTextureObject *) texObj->DriverData;
371
372 if ( t != NULL ) {
373 driSwapOutTextureObject( t );
374 }
375 else {
376 t = (driTextureObject *) mgaAllocTexObj( texObj );
377 if ( t == NULL ) {
378 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
379 return;
380 }
381 }
382
383 _mesa_store_teximage2d( ctx, target, level, internalFormat,
384 width, height, border, format, type,
385 pixels, packing, texObj, texImage );
386 level -= t->firstLevel;
387 if (level >= 0)
388 t->dirty_images[0] |= (1UL << level);
389 }
390
391 static void mgaTexSubImage2D( GLcontext *ctx,
392 GLenum target,
393 GLint level,
394 GLint xoffset, GLint yoffset,
395 GLsizei width, GLsizei height,
396 GLenum format, GLenum type,
397 const GLvoid *pixels,
398 const struct gl_pixelstore_attrib *packing,
399 struct gl_texture_object *texObj,
400 struct gl_texture_image *texImage )
401 {
402 driTextureObject * t = (driTextureObject *) texObj->DriverData;
403
404 assert( t ); /* this _should_ be true */
405 if ( t != NULL ) {
406 driSwapOutTextureObject( t );
407 }
408 else {
409 t = (driTextureObject *) mgaAllocTexObj( texObj );
410 if ( t == NULL ) {
411 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" );
412 return;
413 }
414 }
415
416 _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
417 height, format, type, pixels, packing, texObj,
418 texImage);
419 level -= t->firstLevel;
420 if (level >= 0)
421 t->dirty_images[0] |= (1UL << level);
422 }
423
424
425 /**
426 * Changes variables and flags for a state update, which will happen at the
427 * next UpdateTextureState
428 */
429
430 static void
431 mgaTexParameter( GLcontext *ctx, GLenum target,
432 struct gl_texture_object *tObj,
433 GLenum pname, const GLfloat *params )
434 {
435 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
436 mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
437
438 /* If we don't have a hardware texture, it will be automatically
439 * created with current state before it is used, so we don't have
440 * to do anything now
441 */
442 if ( (t == NULL) ||
443 (target != GL_TEXTURE_2D &&
444 target != GL_TEXTURE_RECTANGLE_NV) ) {
445 return;
446 }
447
448 switch (pname) {
449 case GL_TEXTURE_MIN_FILTER:
450 driSwapOutTextureObject( (driTextureObject *) t );
451 /* FALLTHROUGH */
452 case GL_TEXTURE_MAG_FILTER:
453 FLUSH_BATCH(mmesa);
454 mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter );
455 break;
456
457 case GL_TEXTURE_WRAP_S:
458 case GL_TEXTURE_WRAP_T:
459 FLUSH_BATCH(mmesa);
460 mgaSetTexWrapping(t,tObj->WrapS,tObj->WrapT);
461 break;
462
463 case GL_TEXTURE_BORDER_COLOR:
464 FLUSH_BATCH(mmesa);
465 mgaSetTexBorderColor(t, tObj->BorderColor);
466 break;
467
468 case GL_TEXTURE_BASE_LEVEL:
469 case GL_TEXTURE_MAX_LEVEL:
470 case GL_TEXTURE_MIN_LOD:
471 case GL_TEXTURE_MAX_LOD:
472 /* This isn't the most efficient solution but there doesn't appear to
473 * be a nice alternative. Since there's no LOD clamping,
474 * we just have to rely on loading the right subset of mipmap levels
475 * to simulate a clamped LOD.
476 */
477 driSwapOutTextureObject( (driTextureObject *) t );
478 break;
479
480 default:
481 return;
482 }
483 }
484
485
486 static void
487 mgaBindTexture( GLcontext *ctx, GLenum target,
488 struct gl_texture_object *tObj )
489 {
490 assert( (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_NV) ||
491 (tObj->DriverData != NULL) );
492 }
493
494
495 static void
496 mgaDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
497 {
498 mgaContextPtr mmesa = MGA_CONTEXT( ctx );
499 driTextureObject * t = (driTextureObject *) tObj->DriverData;
500
501 if ( t ) {
502 if ( mmesa ) {
503 FLUSH_BATCH( mmesa );
504 }
505
506 driDestroyTextureObject( t );
507 }
508
509 /* Free mipmap images and the texture object itself */
510 _mesa_delete_texture_object(ctx, tObj);
511 }
512
513
514 /**
515 * Allocate a new texture object.
516 * Called via ctx->Driver.NewTextureObject.
517 * Note: this function will be called during context creation to
518 * allocate the default texture objects.
519 * Note: we could use containment here to 'derive' the driver-specific
520 * texture object from the core mesa gl_texture_object. Not done at this time.
521 */
522 static struct gl_texture_object *
523 mgaNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
524 {
525 struct gl_texture_object *obj;
526 obj = _mesa_new_texture_object(ctx, name, target);
527 mgaAllocTexObj( obj );
528 return obj;
529 }
530
531
532 void
533 mgaInitTextureFuncs( struct dd_function_table *functions )
534 {
535 functions->ChooseTextureFormat = mgaChooseTextureFormat;
536 functions->TexImage2D = mgaTexImage2D;
537 functions->TexSubImage2D = mgaTexSubImage2D;
538 functions->BindTexture = mgaBindTexture;
539 functions->NewTextureObject = mgaNewTextureObject;
540 functions->DeleteTexture = mgaDeleteTexture;
541 functions->IsTextureResident = driIsTextureResident;
542 functions->TexEnv = mgaTexEnv;
543 functions->TexParameter = mgaTexParameter;
544 }