Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / i810 / i810tex.c
1 /*
2  * GLX Hardware Device Driver for Intel i810
3  * Copyright (C) 1999 Keith Whitwell
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  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
21  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  */
24
25 #include "main/glheader.h"
26 #include "main/mtypes.h"
27 #include "main/imports.h"
28 #include "main/simple_list.h"
29 #include "main/enums.h"
30 #include "main/texstore.h"
31 #include "main/teximage.h"
32 #include "main/texobj.h"
33 #include "main/colormac.h"
34 #include "main/mm.h"
35
36 #include "texmem.h"
37
38 #include "i810screen.h"
39 #include "i810_dri.h"
40
41 #include "i810context.h"
42 #include "i810tex.h"
43 #include "i810ioctl.h"
44
45
46 /*
47  * Compute the 'S2.4' lod bias factor from the floating point OpenGL bias.
48  */
49 static GLuint i810ComputeLodBias(GLfloat bias)
50 {
51    int b = (int) (bias * 16.0) + 12;
52    if (b > 63)
53       b = 63;
54    else if (b < -64)
55       b = -64;
56    return (GLuint) (b & MLC_LOD_BIAS_MASK);
57 }
58
59
60 static void i810SetTexWrapping(i810TextureObjectPtr tex,
61                                GLenum swrap, GLenum twrap)
62 {
63    tex->Setup[I810_TEXREG_MCS] &= ~(MCS_U_STATE_MASK| MCS_V_STATE_MASK);
64
65    switch( swrap ) {
66    case GL_REPEAT:
67       tex->Setup[I810_TEXREG_MCS] |= MCS_U_WRAP;
68       break;
69    case GL_CLAMP:
70    case GL_CLAMP_TO_EDGE:
71       tex->Setup[I810_TEXREG_MCS] |= MCS_U_CLAMP;
72       break;
73    case GL_MIRRORED_REPEAT:
74       tex->Setup[I810_TEXREG_MCS] |= MCS_U_MIRROR;
75       break;
76    default:
77       _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
78    }
79
80    switch( twrap ) {
81    case GL_REPEAT:
82       tex->Setup[I810_TEXREG_MCS] |= MCS_V_WRAP;
83       break;
84    case GL_CLAMP:
85    case GL_CLAMP_TO_EDGE:
86       tex->Setup[I810_TEXREG_MCS] |= MCS_V_CLAMP;
87       break;
88    case GL_MIRRORED_REPEAT:
89       tex->Setup[I810_TEXREG_MCS] |= MCS_V_MIRROR;
90       break;
91    default:
92       _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
93    }
94 }
95
96
97 static void i810SetTexFilter(i810ContextPtr imesa, 
98                              i810TextureObjectPtr t, 
99                              GLenum minf, GLenum magf,
100                              GLfloat bias)
101 {
102    t->Setup[I810_TEXREG_MF] &= ~(MF_MIN_MASK|
103                                  MF_MAG_MASK|
104                                  MF_MIP_MASK);
105    t->Setup[I810_TEXREG_MLC] &= ~(MLC_LOD_BIAS_MASK);
106
107    switch (minf) {
108    case GL_NEAREST:
109       t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_NONE;
110       break;
111    case GL_LINEAR:
112       t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_NONE;
113       break;
114    case GL_NEAREST_MIPMAP_NEAREST:
115       t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_NEAREST;
116       if (magf == GL_LINEAR) {
117          /*bias -= 0.5;*/  /* this doesn't work too good */
118       }
119       break;
120    case GL_LINEAR_MIPMAP_NEAREST:
121       t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_NEAREST;
122       break;
123    case GL_NEAREST_MIPMAP_LINEAR:
124       if (IS_I815(imesa)) 
125          t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_LINEAR;
126       else 
127          t->Setup[I810_TEXREG_MF] |= MF_MIN_NEAREST | MF_MIP_DITHER;
128       /*
129       if (magf == GL_LINEAR) {
130          bias -= 0.5;
131       }
132       */
133       bias -= 0.5; /* always biasing here looks better */
134       break;
135    case GL_LINEAR_MIPMAP_LINEAR:
136       if (IS_I815(imesa))
137          t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_LINEAR;
138       else 
139          t->Setup[I810_TEXREG_MF] |= MF_MIN_LINEAR | MF_MIP_DITHER;
140       break;
141    default:
142       return;
143    }
144
145    switch (magf) {
146    case GL_NEAREST: 
147       t->Setup[I810_TEXREG_MF] |= MF_MAG_NEAREST; 
148       break;
149    case GL_LINEAR: 
150       t->Setup[I810_TEXREG_MF] |= MF_MAG_LINEAR; 
151       break;
152    default: 
153       return;
154    }
155
156    t->Setup[I810_TEXREG_MLC] |= i810ComputeLodBias(bias);
157 }
158
159
160 static void
161 i810SetTexBorderColor( i810TextureObjectPtr t, const GLfloat color[4] )
162 {
163    /* Need a fallback.
164     */
165 }
166
167
168 static i810TextureObjectPtr
169 i810AllocTexObj( struct gl_context *ctx, struct gl_texture_object *texObj )
170 {
171    i810TextureObjectPtr t;
172    i810ContextPtr imesa = I810_CONTEXT(ctx);
173
174    t = CALLOC_STRUCT( i810_texture_object_t );
175    texObj->DriverData = t;
176    if ( t != NULL ) {
177       GLfloat bias = ctx->Texture.Unit[ctx->Texture.CurrentUnit].LodBias;
178       /* Initialize non-image-dependent parts of the state:
179        */
180       t->base.tObj = texObj;
181       t->Setup[I810_TEXREG_MI0] = GFX_OP_MAP_INFO;
182       t->Setup[I810_TEXREG_MI1] = MI1_MAP_0; 
183       t->Setup[I810_TEXREG_MI2] = MI2_DIMENSIONS_ARE_LOG2;
184       t->Setup[I810_TEXREG_MLC] = (GFX_OP_MAP_LOD_CTL | 
185                                    MLC_MAP_0 |
186                                    /*MLC_DITHER_WEIGHT_FULL |*/
187                                    MLC_DITHER_WEIGHT_12 |
188                                    MLC_UPDATE_LOD_BIAS |
189                                    0x0);
190       t->Setup[I810_TEXREG_MCS] = (GFX_OP_MAP_COORD_SETS |
191                                    MCS_COORD_0 |
192                                    MCS_UPDATE_NORMALIZED |
193                                    MCS_NORMALIZED_COORDS |
194                                    MCS_UPDATE_V_STATE |
195                                    MCS_V_WRAP |
196                                    MCS_UPDATE_U_STATE |
197                                    MCS_U_WRAP);
198       t->Setup[I810_TEXREG_MF] = (GFX_OP_MAP_FILTER |
199                                   MF_MAP_0 |
200                                   MF_UPDATE_ANISOTROPIC |
201                                   MF_UPDATE_MIP_FILTER |
202                                   MF_UPDATE_MAG_FILTER |
203                                   MF_UPDATE_MIN_FILTER);
204       
205       make_empty_list( & t->base );
206
207       i810SetTexWrapping( t, texObj->Sampler.WrapS, texObj->Sampler.WrapT );
208       /*i830SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );*/
209       i810SetTexFilter( imesa, t, texObj->Sampler.MinFilter, texObj->Sampler.MagFilter, bias );
210       i810SetTexBorderColor( t, texObj->Sampler.BorderColor.f );
211    }
212
213    return t;
214 }
215
216
217 static void i810TexParameter( struct gl_context *ctx, GLenum target,
218                               struct gl_texture_object *tObj,
219                               GLenum pname, const GLfloat *params )
220 {
221    i810ContextPtr imesa = I810_CONTEXT(ctx);
222    i810TextureObjectPtr t = (i810TextureObjectPtr) tObj->DriverData;
223
224    if (!t)
225       return;
226
227    if ( target != GL_TEXTURE_2D )
228       return;
229
230    /* Can't do the update now as we don't know whether to flush
231     * vertices or not.  Setting imesa->new_state means that
232     * i810UpdateTextureState() will be called before any triangles are
233     * rendered.  If a statechange has occurred, it will be detected at
234     * that point, and buffered vertices flushed.  
235     */
236    switch (pname) {
237    case GL_TEXTURE_MIN_FILTER:
238    case GL_TEXTURE_MAG_FILTER:
239       {
240          GLfloat bias = ctx->Texture.Unit[ctx->Texture.CurrentUnit].LodBias;
241          i810SetTexFilter( imesa, t, tObj->Sampler.MinFilter, tObj->Sampler.MagFilter, bias );
242       }
243       break;
244
245    case GL_TEXTURE_WRAP_S:
246    case GL_TEXTURE_WRAP_T:
247       i810SetTexWrapping( t, tObj->Sampler.WrapS, tObj->Sampler.WrapT );
248       break;
249   
250    case GL_TEXTURE_BORDER_COLOR:
251       i810SetTexBorderColor( t, tObj->Sampler.BorderColor.f );
252       break;
253
254    case GL_TEXTURE_BASE_LEVEL:
255    case GL_TEXTURE_MAX_LEVEL:
256    case GL_TEXTURE_MIN_LOD:
257    case GL_TEXTURE_MAX_LOD:
258       /* This isn't the most efficient solution but there doesn't appear to
259        * be a nice alternative for Radeon.  Since there's no LOD clamping,
260        * we just have to rely on loading the right subset of mipmap levels
261        * to simulate a clamped LOD.
262        */
263       I810_FIREVERTICES( I810_CONTEXT(ctx) );
264       driSwapOutTextureObject( (driTextureObject *) t );
265       break;
266
267    default:
268       return;
269    }
270
271    if (t == imesa->CurrentTexObj[0]) {
272       I810_STATECHANGE( imesa, I810_UPLOAD_TEX0 );
273    }
274
275    if (t == imesa->CurrentTexObj[1]) {
276       I810_STATECHANGE( imesa, I810_UPLOAD_TEX1 );
277    }
278 }
279
280
281 /**
282  * Setup hardware bits for new texture environment settings.
283  * 
284  * \todo
285  * Determine whether or not \c param can be used instead of
286  * \c texUnit->EnvColor in the \c GL_TEXTURE_ENV_COLOR case.
287  */
288 static void i810TexEnv( struct gl_context *ctx, GLenum target, 
289                         GLenum pname, const GLfloat *param )
290 {
291    i810ContextPtr imesa = I810_CONTEXT( ctx );
292    const GLuint unit = ctx->Texture.CurrentUnit;
293    const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
294
295    /* Only one env color.  Need a fallback if env colors are different
296     * and texture setup references env color in both units.  
297     */
298    switch (pname) {
299    case GL_TEXTURE_ENV_COLOR: {
300       GLubyte c[4];
301       GLuint envColor;
302
303       UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
304       envColor = PACK_COLOR_8888( c[3], c[0], c[1], c[2] );
305
306       if (imesa->Setup[I810_CTXREG_CF1] != envColor) {
307          I810_STATECHANGE(imesa, I810_UPLOAD_CTX);
308          imesa->Setup[I810_CTXREG_CF1] = envColor;
309       }
310       break;
311    }
312
313    case GL_TEXTURE_ENV_MODE:
314       imesa->TexEnvImageFmt[unit] = 0; /* force recalc of env state */
315       break;
316
317    case GL_TEXTURE_LOD_BIAS: {
318       if ( texUnit->_Current != NULL ) {
319          const struct gl_texture_object *tObj = texUnit->_Current;
320          i810TextureObjectPtr t = (i810TextureObjectPtr) tObj->DriverData;
321
322          t->Setup[I810_TEXREG_MLC] &= ~(MLC_LOD_BIAS_MASK);
323          t->Setup[I810_TEXREG_MLC] |= i810ComputeLodBias(*param);
324       }
325       break;
326    }
327
328    default:
329       break;
330    }
331
332
333
334
335 #if 0
336 static void i810TexImage1D( struct gl_context *ctx, GLenum target, GLint level,
337                             GLint internalFormat,
338                             GLint width, GLint border,
339                             GLenum format, GLenum type, 
340                             const GLvoid *pixels,
341                             const struct gl_pixelstore_attrib *pack,
342                             struct gl_texture_object *texObj,
343                             struct gl_texture_image *texImage )
344 {
345    i810TextureObjectPtr t = (i810TextureObjectPtr) texObj->DriverData;
346    if (t) {
347       i810SwapOutTexObj( imesa, t );
348    }
349 }
350
351 static void i810TexSubImage1D( struct gl_context *ctx, 
352                                GLenum target,
353                                GLint level,     
354                                GLint xoffset,
355                                GLsizei width,
356                                GLenum format, GLenum type,
357                                const GLvoid *pixels,
358                                const struct gl_pixelstore_attrib *pack,
359                                struct gl_texture_object *texObj,
360                                struct gl_texture_image *texImage )
361 {
362 }
363 #endif
364
365
366 static void i810TexImage2D( struct gl_context *ctx, GLenum target, GLint level,
367                             GLint internalFormat,
368                             GLint width, GLint height, GLint border,
369                             GLenum format, GLenum type, const GLvoid *pixels,
370                             const struct gl_pixelstore_attrib *packing,
371                             struct gl_texture_object *texObj,
372                             struct gl_texture_image *texImage )
373 {
374    driTextureObject *t = (driTextureObject *) texObj->DriverData;
375    if (t) {
376       I810_FIREVERTICES( I810_CONTEXT(ctx) );
377       driSwapOutTextureObject( t );
378    }
379    else {
380       t = (driTextureObject *) i810AllocTexObj( ctx, texObj );
381       if (!t) {
382          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
383          return;
384       }
385    }
386    _mesa_store_teximage2d( ctx, target, level, internalFormat,
387                            width, height, border, format, type,
388                            pixels, packing, texObj, texImage );
389 }
390
391 static void i810TexSubImage2D( struct gl_context *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    if (t) {
404      I810_FIREVERTICES( I810_CONTEXT(ctx) );
405      driSwapOutTextureObject( t );
406    }
407    _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, 
408                              height, format, type, pixels, packing, texObj,
409                              texImage);
410 }
411
412
413 static void i810BindTexture( struct gl_context *ctx, GLenum target,
414                              struct gl_texture_object *tObj )
415 {
416    assert( (target != GL_TEXTURE_2D) || (tObj->DriverData != NULL) );
417 }
418
419
420 static void i810DeleteTexture( struct gl_context *ctx, struct gl_texture_object *tObj )
421 {
422    driTextureObject * t = (driTextureObject *) tObj->DriverData;
423    if (t) {
424       i810ContextPtr imesa = I810_CONTEXT( ctx );
425       if (imesa)
426          I810_FIREVERTICES( imesa );
427       driDestroyTextureObject( t );
428    }
429    /* Free mipmap images and the texture object itself */
430    _mesa_delete_texture_object(ctx, tObj);
431 }
432
433 /**
434  * Choose a Mesa texture format to match the requested format.
435  * 
436  * The i810 only supports 5 texture modes that are useful to Mesa.  That
437  * makes this routine pretty simple.
438  */
439 static gl_format
440 i810ChooseTextureFormat( struct gl_context *ctx, GLint internalFormat,
441                          GLenum format, GLenum type )
442 {
443    switch ( internalFormat ) {
444    case 4:
445    case GL_RGBA:
446    case GL_RGBA2:
447    case GL_RGBA4:
448    case GL_RGB5_A1:
449    case GL_RGBA8:
450    case GL_RGB10_A2:
451    case GL_RGBA12:
452    case GL_RGBA16:
453    case GL_COMPRESSED_RGBA:
454       if ( ((format == GL_BGRA) && (type == GL_UNSIGNED_SHORT_1_5_5_5_REV))
455            || ((format == GL_RGBA) && (type == GL_UNSIGNED_SHORT_5_5_5_1))
456            || (internalFormat == GL_RGB5_A1) ) {
457          return MESA_FORMAT_ARGB1555;
458       }
459       return MESA_FORMAT_ARGB4444;
460
461    case 3:
462    case GL_RGB:
463    case GL_COMPRESSED_RGB:
464    case GL_R3_G3_B2:
465    case GL_RGB4:
466    case GL_RGB5:
467    case GL_RGB8:
468    case GL_RGB10:
469    case GL_RGB12:
470    case GL_RGB16:
471       return MESA_FORMAT_RGB565;
472
473    case GL_ALPHA:
474    case GL_ALPHA4:
475    case GL_ALPHA8:
476    case GL_ALPHA12:
477    case GL_ALPHA16:
478    case GL_COMPRESSED_ALPHA:
479    case 1:
480    case GL_LUMINANCE:
481    case GL_LUMINANCE4:
482    case GL_LUMINANCE8:
483    case GL_LUMINANCE12:
484    case GL_LUMINANCE16:
485    case GL_COMPRESSED_LUMINANCE:
486    case 2:
487    case GL_LUMINANCE_ALPHA:
488    case GL_LUMINANCE4_ALPHA4:
489    case GL_LUMINANCE6_ALPHA2:
490    case GL_LUMINANCE8_ALPHA8:
491    case GL_LUMINANCE12_ALPHA4:
492    case GL_LUMINANCE12_ALPHA12:
493    case GL_LUMINANCE16_ALPHA16:
494    case GL_COMPRESSED_LUMINANCE_ALPHA:
495    case GL_INTENSITY:
496    case GL_INTENSITY4:
497    case GL_INTENSITY8:
498    case GL_INTENSITY12:
499    case GL_INTENSITY16:
500    case GL_COMPRESSED_INTENSITY:
501       return MESA_FORMAT_AL88;
502
503    case GL_YCBCR_MESA:
504       if (type == GL_UNSIGNED_SHORT_8_8_MESA ||
505           type == GL_UNSIGNED_BYTE)
506          return MESA_FORMAT_YCBCR;
507       else
508          return MESA_FORMAT_YCBCR_REV;
509
510    default:
511       fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__);
512       return MESA_FORMAT_NONE;
513    }
514
515    return MESA_FORMAT_NONE; /* never get here */
516 }
517
518 /**
519  * Allocate a new texture object.
520  * Called via ctx->Driver.NewTextureObject.
521  * Note: this function will be called during context creation to
522  * allocate the default texture objects.
523  * Note: we could use containment here to 'derive' the driver-specific
524  * texture object from the core mesa gl_texture_object.  Not done at this time.
525  */
526 static struct gl_texture_object *
527 i810NewTextureObject( struct gl_context *ctx, GLuint name, GLenum target )
528 {
529    struct gl_texture_object *obj;
530    obj = _mesa_new_texture_object(ctx, name, target);
531    i810AllocTexObj( ctx, obj );
532    return obj;
533 }
534
535 void i810InitTextureFuncs( struct dd_function_table *functions )
536 {
537    functions->ChooseTextureFormat = i810ChooseTextureFormat;
538    functions->TexImage2D = i810TexImage2D;
539    functions->TexSubImage2D = i810TexSubImage2D;
540    functions->BindTexture = i810BindTexture;
541    functions->NewTextureObject = i810NewTextureObject;
542    functions->DeleteTexture = i810DeleteTexture;
543    functions->TexParameter = i810TexParameter;
544    functions->TexEnv = i810TexEnv;
545    functions->IsTextureResident = driIsTextureResident;
546 }