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