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