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