Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / r200 / r200_tex.c
1 /*
2 Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
3
4 The Weather Channel (TM) funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86 license.
6 This notice must be preserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29 /*
30  * Authors:
31  *   Keith Whitwell <keith@tungstengraphics.com>
32  */
33
34 #include "main/glheader.h"
35 #include "main/imports.h"
36 #include "main/colormac.h"
37 #include "main/context.h"
38 #include "main/enums.h"
39 #include "main/image.h"
40 #include "main/mfeatures.h"
41 #include "main/simple_list.h"
42 #include "main/texstore.h"
43 #include "main/teximage.h"
44 #include "main/texobj.h"
45
46 #include "radeon_mipmap_tree.h"
47 #include "r200_context.h"
48 #include "r200_ioctl.h"
49 #include "r200_tex.h"
50
51 #include "xmlpool.h"
52
53
54
55 /**
56  * Set the texture wrap modes.
57  * 
58  * \param t Texture object whose wrap modes are to be set
59  * \param swrap Wrap mode for the \a s texture coordinate
60  * \param twrap Wrap mode for the \a t texture coordinate
61  */
62
63 static void r200SetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap, GLenum rwrap )
64 {
65    GLboolean  is_clamp = GL_FALSE;
66    GLboolean  is_clamp_to_border = GL_FALSE;
67    struct gl_texture_object *tObj = &t->base;
68
69    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
70                 "%s(tex %p) sw %s, tw %s, rw %s\n",
71                 __func__, t,
72                 _mesa_lookup_enum_by_nr(swrap),
73                 _mesa_lookup_enum_by_nr(twrap),
74                 _mesa_lookup_enum_by_nr(rwrap));
75
76    t->pp_txfilter &= ~(R200_CLAMP_S_MASK | R200_CLAMP_T_MASK | R200_BORDER_MODE_D3D);
77
78    switch ( swrap ) {
79    case GL_REPEAT:
80       t->pp_txfilter |= R200_CLAMP_S_WRAP;
81       break;
82    case GL_CLAMP:
83       t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
84       is_clamp = GL_TRUE;
85       break;
86    case GL_CLAMP_TO_EDGE:
87       t->pp_txfilter |= R200_CLAMP_S_CLAMP_LAST;
88       break;
89    case GL_CLAMP_TO_BORDER:
90       t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
91       is_clamp_to_border = GL_TRUE;
92       break;
93    case GL_MIRRORED_REPEAT:
94       t->pp_txfilter |= R200_CLAMP_S_MIRROR;
95       break;
96    case GL_MIRROR_CLAMP_EXT:
97       t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
98       is_clamp = GL_TRUE;
99       break;
100    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
101       t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_LAST;
102       break;
103    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
104       t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
105       is_clamp_to_border = GL_TRUE;
106       break;
107    default:
108       _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
109    }
110
111    if (tObj->Target != GL_TEXTURE_1D) {
112       switch ( twrap ) {
113       case GL_REPEAT:
114          t->pp_txfilter |= R200_CLAMP_T_WRAP;
115          break;
116       case GL_CLAMP:
117          t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
118          is_clamp = GL_TRUE;
119          break;
120       case GL_CLAMP_TO_EDGE:
121          t->pp_txfilter |= R200_CLAMP_T_CLAMP_LAST;
122          break;
123       case GL_CLAMP_TO_BORDER:
124          t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
125          is_clamp_to_border = GL_TRUE;
126          break;
127       case GL_MIRRORED_REPEAT:
128          t->pp_txfilter |= R200_CLAMP_T_MIRROR;
129          break;
130       case GL_MIRROR_CLAMP_EXT:
131          t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
132          is_clamp = GL_TRUE;
133          break;
134       case GL_MIRROR_CLAMP_TO_EDGE_EXT:
135          t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_LAST;
136          break;
137       case GL_MIRROR_CLAMP_TO_BORDER_EXT:
138          t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
139          is_clamp_to_border = GL_TRUE;
140          break;
141       default:
142          _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
143       }
144    }
145
146    t->pp_txformat_x &= ~R200_CLAMP_Q_MASK;
147
148    switch ( rwrap ) {
149    case GL_REPEAT:
150       t->pp_txformat_x |= R200_CLAMP_Q_WRAP;
151       break;
152    case GL_CLAMP:
153       t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
154       is_clamp = GL_TRUE;
155       break;
156    case GL_CLAMP_TO_EDGE:
157       t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_LAST;
158       break;
159    case GL_CLAMP_TO_BORDER:
160       t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
161       is_clamp_to_border = GL_TRUE;
162       break;
163    case GL_MIRRORED_REPEAT:
164       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR;
165       break;
166    case GL_MIRROR_CLAMP_EXT:
167       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
168       is_clamp = GL_TRUE;
169       break;
170    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
171       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_LAST;
172       break;
173    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
174       t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
175       is_clamp_to_border = GL_TRUE;
176       break;
177    default:
178       _mesa_problem(NULL, "bad R wrap mode in %s", __FUNCTION__);
179    }
180
181    if ( is_clamp_to_border ) {
182       t->pp_txfilter |= R200_BORDER_MODE_D3D;
183    }
184
185    t->border_fallback = (is_clamp && is_clamp_to_border);
186 }
187
188 static void r200SetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
189 {
190    t->pp_txfilter &= ~R200_MAX_ANISO_MASK;
191    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
192         "%s(tex %p) max %f.\n",
193         __func__, t, max);
194
195    if ( max <= 1.0 ) {
196       t->pp_txfilter |= R200_MAX_ANISO_1_TO_1;
197    } else if ( max <= 2.0 ) {
198       t->pp_txfilter |= R200_MAX_ANISO_2_TO_1;
199    } else if ( max <= 4.0 ) {
200       t->pp_txfilter |= R200_MAX_ANISO_4_TO_1;
201    } else if ( max <= 8.0 ) {
202       t->pp_txfilter |= R200_MAX_ANISO_8_TO_1;
203    } else {
204       t->pp_txfilter |= R200_MAX_ANISO_16_TO_1;
205    }
206 }
207
208 /**
209  * Set the texture magnification and minification modes.
210  * 
211  * \param t Texture whose filter modes are to be set
212  * \param minf Texture minification mode
213  * \param magf Texture magnification mode
214  */
215
216 static void r200SetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
217 {
218    GLuint anisotropy = (t->pp_txfilter & R200_MAX_ANISO_MASK);
219
220    /* Force revalidation to account for switches from/to mipmapping. */
221    t->validated = GL_FALSE;
222
223    t->pp_txfilter &= ~(R200_MIN_FILTER_MASK | R200_MAG_FILTER_MASK);
224    t->pp_txformat_x &= ~R200_VOLUME_FILTER_MASK;
225
226    radeon_print(RADEON_TEXTURE, RADEON_TRACE,
227         "%s(tex %p) minf %s, maxf %s, anisotropy %d.\n",
228         __func__, t,
229         _mesa_lookup_enum_by_nr(minf),
230         _mesa_lookup_enum_by_nr(magf),
231         anisotropy);
232
233    if ( anisotropy == R200_MAX_ANISO_1_TO_1 ) {
234       switch ( minf ) {
235       case GL_NEAREST:
236          t->pp_txfilter |= R200_MIN_FILTER_NEAREST;
237          break;
238       case GL_LINEAR:
239          t->pp_txfilter |= R200_MIN_FILTER_LINEAR;
240          break;
241       case GL_NEAREST_MIPMAP_NEAREST:
242          t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_NEAREST;
243          break;
244       case GL_NEAREST_MIPMAP_LINEAR:
245          t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_NEAREST;
246          break;
247       case GL_LINEAR_MIPMAP_NEAREST:
248          t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_LINEAR;
249          break;
250       case GL_LINEAR_MIPMAP_LINEAR:
251          t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_LINEAR;
252          break;
253       }
254    } else {
255       switch ( minf ) {
256       case GL_NEAREST:
257          t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST;
258          break;
259       case GL_LINEAR:
260          t->pp_txfilter |= R200_MIN_FILTER_ANISO_LINEAR;
261          break;
262       case GL_NEAREST_MIPMAP_NEAREST:
263       case GL_LINEAR_MIPMAP_NEAREST:
264          t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
265          break;
266       case GL_NEAREST_MIPMAP_LINEAR:
267       case GL_LINEAR_MIPMAP_LINEAR:
268          t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
269          break;
270       }
271    }
272
273    /* Note we don't have 3D mipmaps so only use the mag filter setting
274     * to set the 3D texture filter mode.
275     */
276    switch ( magf ) {
277    case GL_NEAREST:
278       t->pp_txfilter |= R200_MAG_FILTER_NEAREST;
279       t->pp_txformat_x |= R200_VOLUME_FILTER_NEAREST;
280       break;
281    case GL_LINEAR:
282       t->pp_txfilter |= R200_MAG_FILTER_LINEAR;
283       t->pp_txformat_x |= R200_VOLUME_FILTER_LINEAR;
284       break;
285    }
286 }
287
288 static void r200SetTexBorderColor( radeonTexObjPtr t, const GLfloat color[4] )
289 {
290    GLubyte c[4];
291    CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
292    CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
293    CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
294    CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
295    t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
296 }
297
298 static void r200TexEnv( struct gl_context *ctx, GLenum target,
299                           GLenum pname, const GLfloat *param )
300 {
301    r200ContextPtr rmesa = R200_CONTEXT(ctx);
302    GLuint unit = ctx->Texture.CurrentUnit;
303    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
304
305    radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_VERBOSE, "%s( %s )\n",
306                __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
307
308    /* This is incorrect: Need to maintain this data for each of
309     * GL_TEXTURE_{123}D, GL_TEXTURE_RECTANGLE_NV, etc, and switch
310     * between them according to _ReallyEnabled.
311     */
312    switch ( pname ) {
313    case GL_TEXTURE_ENV_COLOR: {
314       GLubyte c[4];
315       GLuint envColor;
316       UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
317       envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
318       if ( rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] != envColor ) {
319          R200_STATECHANGE( rmesa, tf );
320          rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] = envColor;
321       }
322       break;
323    }
324
325    case GL_TEXTURE_LOD_BIAS_EXT: {
326       GLfloat bias, min;
327       GLuint b;
328       const int fixed_one = R200_LOD_BIAS_FIXED_ONE;
329
330       /* The R200's LOD bias is a signed 2's complement value with a
331        * range of -16.0 <= bias < 16.0. 
332        *
333        * NOTE: Add a small bias to the bias for conform mipsel.c test.
334        */
335       bias = *param;
336       min = driQueryOptionb (&rmesa->radeon.optionCache, "no_neg_lod_bias") ?
337           0.0 : -16.0;
338       bias = CLAMP( bias, min, 16.0 );
339       b = ((int)(bias * fixed_one)
340                 + R200_LOD_BIAS_CORRECTION) & R200_LOD_BIAS_MASK;
341       
342       if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] & R200_LOD_BIAS_MASK) != b ) {
343          R200_STATECHANGE( rmesa, tex[unit] );
344          rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] &= ~R200_LOD_BIAS_MASK;
345          rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] |= b;
346       }
347       break;
348    }
349    case GL_COORD_REPLACE_ARB:
350       if (ctx->Point.PointSprite) {
351          R200_STATECHANGE( rmesa, spr );
352          if ((GLenum)param[0]) {
353             rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] |= R200_PS_GEN_TEX_0 << unit;
354          } else {
355             rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] &= ~(R200_PS_GEN_TEX_0 << unit);
356          }
357       }
358       break;
359    default:
360       return;
361    }
362 }
363
364
365 /**
366  * Changes variables and flags for a state update, which will happen at the
367  * next UpdateTextureState
368  */
369
370 static void r200TexParameter( struct gl_context *ctx, GLenum target,
371                                 struct gl_texture_object *texObj,
372                                 GLenum pname, const GLfloat *params )
373 {
374    radeonTexObj* t = radeon_tex_obj(texObj);
375
376    radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_VERBOSE,
377                 "%s(%p, tex %p)  target %s, pname %s\n",
378                 __FUNCTION__, ctx, texObj,
379                 _mesa_lookup_enum_by_nr( target ),
380                _mesa_lookup_enum_by_nr( pname ) );
381
382    switch ( pname ) {
383    case GL_TEXTURE_MIN_FILTER:
384    case GL_TEXTURE_MAG_FILTER:
385    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
386       r200SetTexMaxAnisotropy( t, texObj->Sampler.MaxAnisotropy );
387       r200SetTexFilter( t, texObj->Sampler.MinFilter, texObj->Sampler.MagFilter );
388       break;
389
390    case GL_TEXTURE_WRAP_S:
391    case GL_TEXTURE_WRAP_T:
392    case GL_TEXTURE_WRAP_R:
393       r200SetTexWrap( t, texObj->Sampler.WrapS, texObj->Sampler.WrapT, texObj->Sampler.WrapR );
394       break;
395
396    case GL_TEXTURE_BORDER_COLOR:
397       r200SetTexBorderColor( t, texObj->Sampler.BorderColor.f );
398       break;
399
400    case GL_TEXTURE_BASE_LEVEL:
401    case GL_TEXTURE_MAX_LEVEL:
402    case GL_TEXTURE_MIN_LOD:
403    case GL_TEXTURE_MAX_LOD:
404       t->validated = GL_FALSE;
405       break;
406
407    default:
408       return;
409    }
410 }
411
412
413 static void r200DeleteTexture(struct gl_context * ctx, struct gl_texture_object *texObj)
414 {
415    r200ContextPtr rmesa = R200_CONTEXT(ctx);
416    radeonTexObj* t = radeon_tex_obj(texObj);
417
418    radeon_print(RADEON_TEXTURE | RADEON_STATE, RADEON_NORMAL,
419            "%s( %p (target = %s) )\n", __FUNCTION__,
420            (void *)texObj,
421            _mesa_lookup_enum_by_nr(texObj->Target));
422
423    if (rmesa) {
424       int i;
425       radeon_firevertices(&rmesa->radeon);
426       for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
427          if ( t == rmesa->state.texture.unit[i].texobj ) {
428             rmesa->state.texture.unit[i].texobj = NULL;
429             rmesa->hw.tex[i].dirty = GL_FALSE;
430             rmesa->hw.cube[i].dirty = GL_FALSE;
431          }
432       }      
433    }
434
435    radeon_miptree_unreference(&t->mt);
436
437    _mesa_delete_texture_object(ctx, texObj);
438 }
439
440 /* Need:  
441  *  - Same GEN_MODE for all active bits
442  *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
443  *  - STRQ presumably all supported (matrix means incoming R values
444  *    can end up in STQ, this has implications for vertex support,
445  *    presumably ok if maos is used, though?)
446  *  
447  * Basically impossible to do this on the fly - just collect some
448  * basic info & do the checks from ValidateState().
449  */
450 static void r200TexGen( struct gl_context *ctx,
451                           GLenum coord,
452                           GLenum pname,
453                           const GLfloat *params )
454 {
455    r200ContextPtr rmesa = R200_CONTEXT(ctx);
456    GLuint unit = ctx->Texture.CurrentUnit;
457    rmesa->recheck_texgen[unit] = GL_TRUE;
458 }
459
460
461 /**
462  * Allocate a new texture object.
463  * Called via ctx->Driver.NewTextureObject.
464  * Note: this function will be called during context creation to
465  * allocate the default texture objects.
466  * Fixup MaxAnisotropy according to user preference.
467  */
468 static struct gl_texture_object *r200NewTextureObject(struct gl_context * ctx,
469                                                       GLuint name,
470                                                       GLenum target)
471 {
472    r200ContextPtr rmesa = R200_CONTEXT(ctx);
473    radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
474
475
476    radeon_print(RADEON_STATE | RADEON_TEXTURE, RADEON_NORMAL,
477            "%s(%p) target %s, new texture %p.\n",
478            __FUNCTION__, ctx,
479            _mesa_lookup_enum_by_nr(target), t);
480
481    _mesa_initialize_texture_object(&t->base, name, target);
482    t->base.Sampler.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
483
484    /* Initialize hardware state */
485    r200SetTexWrap( t, t->base.Sampler.WrapS, t->base.Sampler.WrapT, t->base.Sampler.WrapR );
486    r200SetTexMaxAnisotropy( t, t->base.Sampler.MaxAnisotropy );
487    r200SetTexFilter(t, t->base.Sampler.MinFilter, t->base.Sampler.MagFilter);
488    r200SetTexBorderColor(t, t->base.Sampler.BorderColor.f);
489
490    return &t->base;
491 }
492
493
494
495 void r200InitTextureFuncs( radeonContextPtr radeon, struct dd_function_table *functions )
496 {
497    /* Note: we only plug in the functions we implement in the driver
498     * since _mesa_init_driver_functions() was already called.
499     */
500    functions->ChooseTextureFormat       = radeonChooseTextureFormat_mesa;
501    functions->TexImage1D                = radeonTexImage1D;
502    functions->TexImage2D                = radeonTexImage2D;
503 #if ENABLE_HW_3D_TEXTURE
504    functions->TexImage3D                = radeonTexImage3D;
505 #else
506    functions->TexImage3D                = _mesa_store_teximage3d;
507 #endif
508    functions->TexSubImage1D             = radeonTexSubImage1D;
509    functions->TexSubImage2D             = radeonTexSubImage2D;
510 #if ENABLE_HW_3D_TEXTURE
511    functions->TexSubImage3D             = radeonTexSubImage3D;
512 #else
513    functions->TexSubImage3D             = _mesa_store_texsubimage3d;
514 #endif
515    functions->GetTexImage               = radeonGetTexImage;
516    functions->GetCompressedTexImage     = radeonGetCompressedTexImage;
517    functions->NewTextureObject          = r200NewTextureObject;
518    //   functions->BindTexture          = r200BindTexture;
519    functions->DeleteTexture             = r200DeleteTexture;
520    functions->IsTextureResident         = driIsTextureResident;
521
522    functions->TexEnv                    = r200TexEnv;
523    functions->TexParameter              = r200TexParameter;
524    functions->TexGen                    = r200TexGen;
525
526    functions->CompressedTexImage2D      = radeonCompressedTexImage2D;
527    functions->CompressedTexSubImage2D   = radeonCompressedTexSubImage2D;
528
529    if (radeon->radeonScreen->kernel_mm) {
530       functions->CopyTexImage2D = radeonCopyTexImage2D;
531       functions->CopyTexSubImage2D = radeonCopyTexSubImage2D;
532    }
533
534    functions->GenerateMipmap = radeonGenerateMipmap;
535
536    functions->NewTextureImage = radeonNewTextureImage;
537    functions->FreeTexImageData = radeonFreeTexImageData;
538    functions->MapTexture = radeonMapTexture;
539    functions->UnmapTexture = radeonUnmapTexture;
540
541 #if FEATURE_OES_EGL_image
542    functions->EGLImageTargetTexture2D = radeon_image_target_texture_2d;
543 #endif
544
545    driInitTextureFormats();
546
547 }