Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / radeon / radeon_tex.c
1 /*
2 Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
3                      VA Linux Systems Inc., Fremont, California.
4
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial
17 portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 */
27
28 /*
29  * Authors:
30  *    Gareth Hughes <gareth@valinux.com>
31  *    Brian Paul <brianp@valinux.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_context.h"
47 #include "radeon_mipmap_tree.h"
48 #include "radeon_ioctl.h"
49 #include "radeon_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 radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap )
64 {
65    GLboolean  is_clamp = GL_FALSE;
66    GLboolean  is_clamp_to_border = GL_FALSE;
67
68    t->pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK | RADEON_BORDER_MODE_D3D);
69
70    switch ( swrap ) {
71    case GL_REPEAT:
72       t->pp_txfilter |= RADEON_CLAMP_S_WRAP;
73       break;
74    case GL_CLAMP:
75       t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
76       is_clamp = GL_TRUE;
77       break;
78    case GL_CLAMP_TO_EDGE:
79       t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST;
80       break;
81    case GL_CLAMP_TO_BORDER:
82       t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL;
83       is_clamp_to_border = GL_TRUE;
84       break;
85    case GL_MIRRORED_REPEAT:
86       t->pp_txfilter |= RADEON_CLAMP_S_MIRROR;
87       break;
88    case GL_MIRROR_CLAMP_EXT:
89       t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
90       is_clamp = GL_TRUE;
91       break;
92    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
93       t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_LAST;
94       break;
95    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
96       t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL;
97       is_clamp_to_border = GL_TRUE;
98       break;
99    default:
100       _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
101    }
102
103    switch ( twrap ) {
104    case GL_REPEAT:
105       t->pp_txfilter |= RADEON_CLAMP_T_WRAP;
106       break;
107    case GL_CLAMP:
108       t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
109       is_clamp = GL_TRUE;
110       break;
111    case GL_CLAMP_TO_EDGE:
112       t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST;
113       break;
114    case GL_CLAMP_TO_BORDER:
115       t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL;
116       is_clamp_to_border = GL_TRUE;
117       break;
118    case GL_MIRRORED_REPEAT:
119       t->pp_txfilter |= RADEON_CLAMP_T_MIRROR;
120       break;
121    case GL_MIRROR_CLAMP_EXT:
122       t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
123       is_clamp = GL_TRUE;
124       break;
125    case GL_MIRROR_CLAMP_TO_EDGE_EXT:
126       t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_LAST;
127       break;
128    case GL_MIRROR_CLAMP_TO_BORDER_EXT:
129       t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL;
130       is_clamp_to_border = GL_TRUE;
131       break;
132    default:
133       _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
134    }
135
136    if ( is_clamp_to_border ) {
137       t->pp_txfilter |= RADEON_BORDER_MODE_D3D;
138    }
139
140    t->border_fallback = (is_clamp && is_clamp_to_border);
141 }
142
143 static void radeonSetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
144 {
145    t->pp_txfilter &= ~RADEON_MAX_ANISO_MASK;
146
147    if ( max == 1.0 ) {
148       t->pp_txfilter |= RADEON_MAX_ANISO_1_TO_1;
149    } else if ( max <= 2.0 ) {
150       t->pp_txfilter |= RADEON_MAX_ANISO_2_TO_1;
151    } else if ( max <= 4.0 ) {
152       t->pp_txfilter |= RADEON_MAX_ANISO_4_TO_1;
153    } else if ( max <= 8.0 ) {
154       t->pp_txfilter |= RADEON_MAX_ANISO_8_TO_1;
155    } else {
156       t->pp_txfilter |= RADEON_MAX_ANISO_16_TO_1;
157    }
158 }
159
160 /**
161  * Set the texture magnification and minification modes.
162  * 
163  * \param t Texture whose filter modes are to be set
164  * \param minf Texture minification mode
165  * \param magf Texture magnification mode
166  */
167
168 static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
169 {
170    GLuint anisotropy = (t->pp_txfilter & RADEON_MAX_ANISO_MASK);
171
172    /* Force revalidation to account for switches from/to mipmapping. */
173    t->validated = GL_FALSE;
174
175    t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK);
176
177    /* r100 chips can't handle mipmaps/aniso for cubemap/volume textures */
178    if ( t->base.Target == GL_TEXTURE_CUBE_MAP ) {
179       switch ( minf ) {
180       case GL_NEAREST:
181       case GL_NEAREST_MIPMAP_NEAREST:
182       case GL_NEAREST_MIPMAP_LINEAR:
183          t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
184          break;
185       case GL_LINEAR:
186       case GL_LINEAR_MIPMAP_NEAREST:
187       case GL_LINEAR_MIPMAP_LINEAR:
188          t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
189          break;
190       default:
191          break;
192       }
193    }
194    else if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) {
195       switch ( minf ) {
196       case GL_NEAREST:
197          t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST;
198          break;
199       case GL_LINEAR:
200          t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR;
201          break;
202       case GL_NEAREST_MIPMAP_NEAREST:
203          t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST;
204          break;
205       case GL_NEAREST_MIPMAP_LINEAR:
206          t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST;
207          break;
208       case GL_LINEAR_MIPMAP_NEAREST:
209          t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR;
210          break;
211       case GL_LINEAR_MIPMAP_LINEAR:
212          t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR;
213          break;
214       }
215    } else {
216       switch ( minf ) {
217       case GL_NEAREST:
218          t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST;
219          break;
220       case GL_LINEAR:
221          t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_LINEAR;
222          break;
223       case GL_NEAREST_MIPMAP_NEAREST:
224       case GL_LINEAR_MIPMAP_NEAREST:
225          t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
226          break;
227       case GL_NEAREST_MIPMAP_LINEAR:
228       case GL_LINEAR_MIPMAP_LINEAR:
229          t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
230          break;
231       }
232    }
233
234    switch ( magf ) {
235    case GL_NEAREST:
236       t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST;
237       break;
238    case GL_LINEAR:
239       t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR;
240       break;
241    }
242 }
243
244 static void radeonSetTexBorderColor( radeonTexObjPtr t, const GLfloat color[4] )
245 {
246    GLubyte c[4];
247    CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
248    CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
249    CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
250    CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
251    t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
252 }
253
254 #define SCALED_FLOAT_TO_BYTE( x, scale ) \
255                 (((GLuint)((255.0F / scale) * (x))) / 2)
256
257 static void radeonTexEnv( struct gl_context *ctx, GLenum target,
258                           GLenum pname, const GLfloat *param )
259 {
260    r100ContextPtr rmesa = R100_CONTEXT(ctx);
261    GLuint unit = ctx->Texture.CurrentUnit;
262    struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
263
264    if ( RADEON_DEBUG & RADEON_STATE ) {
265       fprintf( stderr, "%s( %s )\n",
266                __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
267    }
268
269    switch ( pname ) {
270    case GL_TEXTURE_ENV_COLOR: {
271       GLubyte c[4];
272       GLuint envColor;
273       UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
274       envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
275       if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) {
276          RADEON_STATECHANGE( rmesa, tex[unit] );
277          rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor;
278       }
279       break;
280    }
281
282    case GL_TEXTURE_LOD_BIAS_EXT: {
283       GLfloat bias, min;
284       GLuint b;
285
286       /* The Radeon's LOD bias is a signed 2's complement value with a
287        * range of -1.0 <= bias < 4.0.  We break this into two linear
288        * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping
289        * [0.0,4.0] to [0,127].
290        */
291       min = driQueryOptionb (&rmesa->radeon.optionCache, "no_neg_lod_bias") ?
292           0.0 : -1.0;
293       bias = CLAMP( *param, min, 4.0 );
294       if ( bias == 0 ) {
295          b = 0;
296       } else if ( bias > 0 ) {
297          b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 4.0 )) << RADEON_LOD_BIAS_SHIFT;
298       } else {
299          b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 1.0 )) << RADEON_LOD_BIAS_SHIFT;
300       }
301       if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] & RADEON_LOD_BIAS_MASK) != b ) {
302          RADEON_STATECHANGE( rmesa, tex[unit] );
303          rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] &= ~RADEON_LOD_BIAS_MASK;
304          rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] |= (b & RADEON_LOD_BIAS_MASK);
305       }
306       break;
307    }
308
309    default:
310       return;
311    }
312 }
313
314
315 /**
316  * Changes variables and flags for a state update, which will happen at the
317  * next UpdateTextureState
318  */
319
320 static void radeonTexParameter( struct gl_context *ctx, GLenum target,
321                                 struct gl_texture_object *texObj,
322                                 GLenum pname, const GLfloat *params )
323 {
324    radeonTexObj* t = radeon_tex_obj(texObj);
325
326    radeon_print(RADEON_TEXTURE, RADEON_VERBOSE, "%s( %s )\n", __FUNCTION__,
327                _mesa_lookup_enum_by_nr( pname ) );
328
329    switch ( pname ) {
330    case GL_TEXTURE_MIN_FILTER:
331    case GL_TEXTURE_MAG_FILTER:
332    case GL_TEXTURE_MAX_ANISOTROPY_EXT:
333       radeonSetTexMaxAnisotropy( t, texObj->Sampler.MaxAnisotropy );
334       radeonSetTexFilter( t, texObj->Sampler.MinFilter, texObj->Sampler.MagFilter );
335       break;
336
337    case GL_TEXTURE_WRAP_S:
338    case GL_TEXTURE_WRAP_T:
339       radeonSetTexWrap( t, texObj->Sampler.WrapS, texObj->Sampler.WrapT );
340       break;
341
342    case GL_TEXTURE_BORDER_COLOR:
343       radeonSetTexBorderColor( t, texObj->Sampler.BorderColor.f );
344       break;
345
346    case GL_TEXTURE_BASE_LEVEL:
347    case GL_TEXTURE_MAX_LEVEL:
348    case GL_TEXTURE_MIN_LOD:
349    case GL_TEXTURE_MAX_LOD:
350       t->validated = GL_FALSE;
351       break;
352
353    default:
354       return;
355    }
356 }
357
358 static void radeonDeleteTexture( struct gl_context *ctx,
359                                  struct gl_texture_object *texObj )
360 {
361    r100ContextPtr rmesa = R100_CONTEXT(ctx);
362    radeonTexObj* t = radeon_tex_obj(texObj);
363    int i;
364
365    radeon_print(RADEON_TEXTURE, RADEON_NORMAL,
366          "%s( %p (target = %s) )\n", __FUNCTION__, (void *)texObj,
367                _mesa_lookup_enum_by_nr( texObj->Target ) );
368
369    if ( rmesa ) {
370      radeon_firevertices(&rmesa->radeon);
371      for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
372        if ( t == rmesa->state.texture.unit[i].texobj ) {
373          rmesa->state.texture.unit[i].texobj = NULL;
374          rmesa->hw.tex[i].dirty = GL_FALSE;
375          rmesa->hw.cube[i].dirty = GL_FALSE;
376        }
377      }
378    }
379
380    radeon_miptree_unreference(&t->mt);
381
382    /* Free mipmap images and the texture object itself */
383    _mesa_delete_texture_object(ctx, texObj);
384 }
385
386 /* Need:  
387  *  - Same GEN_MODE for all active bits
388  *  - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
389  *  - STRQ presumably all supported (matrix means incoming R values
390  *    can end up in STQ, this has implications for vertex support,
391  *    presumably ok if maos is used, though?)
392  *  
393  * Basically impossible to do this on the fly - just collect some
394  * basic info & do the checks from ValidateState().
395  */
396 static void radeonTexGen( struct gl_context *ctx,
397                           GLenum coord,
398                           GLenum pname,
399                           const GLfloat *params )
400 {
401    r100ContextPtr rmesa = R100_CONTEXT(ctx);
402    GLuint unit = ctx->Texture.CurrentUnit;
403    rmesa->recheck_texgen[unit] = GL_TRUE;
404 }
405
406 /**
407  * Allocate a new texture object.
408  * Called via ctx->Driver.NewTextureObject.
409  * Note: we could use containment here to 'derive' the driver-specific
410  * texture object from the core mesa gl_texture_object.  Not done at this time.
411  */
412 static struct gl_texture_object *
413 radeonNewTextureObject( struct gl_context *ctx, GLuint name, GLenum target )
414 {
415    r100ContextPtr rmesa = R100_CONTEXT(ctx);
416    radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
417
418    _mesa_initialize_texture_object(&t->base, name, target);
419    t->base.Sampler.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
420
421    t->border_fallback = GL_FALSE;
422
423    t->pp_txfilter = RADEON_BORDER_MODE_OGL;
424    t->pp_txformat = (RADEON_TXFORMAT_ENDIAN_NO_SWAP |
425                      RADEON_TXFORMAT_PERSPECTIVE_ENABLE);
426    
427    radeonSetTexWrap( t, t->base.Sampler.WrapS, t->base.Sampler.WrapT );
428    radeonSetTexMaxAnisotropy( t, t->base.Sampler.MaxAnisotropy );
429    radeonSetTexFilter( t, t->base.Sampler.MinFilter, t->base.Sampler.MagFilter );
430    radeonSetTexBorderColor( t, t->base.Sampler.BorderColor.f );
431    return &t->base;
432 }
433
434
435
436 void radeonInitTextureFuncs( radeonContextPtr radeon, struct dd_function_table *functions )
437 {
438    functions->ChooseTextureFormat       = radeonChooseTextureFormat_mesa;
439    functions->TexImage1D                = radeonTexImage1D;
440    functions->TexImage2D                = radeonTexImage2D;
441    functions->TexSubImage1D             = radeonTexSubImage1D;
442    functions->TexSubImage2D             = radeonTexSubImage2D;
443    functions->GetTexImage               = radeonGetTexImage;
444    functions->GetCompressedTexImage     = radeonGetCompressedTexImage;
445
446    functions->NewTextureObject          = radeonNewTextureObject;
447    //   functions->BindTexture          = radeonBindTexture;
448    functions->DeleteTexture             = radeonDeleteTexture;
449
450    functions->TexEnv                    = radeonTexEnv;
451    functions->TexParameter              = radeonTexParameter;
452    functions->TexGen                    = radeonTexGen;
453
454    functions->CompressedTexImage2D      = radeonCompressedTexImage2D;
455    functions->CompressedTexSubImage2D   = radeonCompressedTexSubImage2D;
456
457    if (radeon->radeonScreen->kernel_mm) {
458       functions->CopyTexImage2D = radeonCopyTexImage2D;
459       functions->CopyTexSubImage2D = radeonCopyTexSubImage2D;
460    }
461
462    functions->GenerateMipmap = radeonGenerateMipmap;
463
464    functions->NewTextureImage = radeonNewTextureImage;
465    functions->FreeTexImageData = radeonFreeTexImageData;
466    functions->MapTexture = radeonMapTexture;
467    functions->UnmapTexture = radeonUnmapTexture;
468
469 #if FEATURE_OES_EGL_image
470    functions->EGLImageTargetTexture2D = radeon_image_target_texture_2d;
471 #endif
472
473    driInitTextureFormats();
474 }