r200/r300: port r200 texture handling to common code
[mesa.git] / src / mesa / drivers / dri / r200 / r200_tex.c
1 /*
2 Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
3
4 The Weather Channel (TM) funded Tungsten Graphics to develop the
5 initial release of the Radeon 8500 driver under the XFree86 license.
6 This notice must be preserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15
16 The above copyright notice and this permission notice (including the
17 next paragraph) shall be included in all copies or substantial
18 portions of the Software.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
24 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29 /*
30 * Authors:
31 * Keith Whitwell <keith@tungstengraphics.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/simple_list.h"
41 #include "main/texformat.h"
42 #include "main/texstore.h"
43 #include "main/teximage.h"
44 #include "main/texobj.h"
45
46 #include "texmem.h"
47
48 #include "radeon_mipmap_tree.h"
49 #include "r200_context.h"
50 #include "r200_state.h"
51 #include "r200_ioctl.h"
52 #include "r200_swtcl.h"
53 #include "r200_tex.h"
54
55 #include "xmlpool.h"
56
57
58
59 /**
60 * Set the texture wrap modes.
61 *
62 * \param t Texture object whose wrap modes are to be set
63 * \param swrap Wrap mode for the \a s texture coordinate
64 * \param twrap Wrap mode for the \a t texture coordinate
65 */
66
67 static void r200SetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap, GLenum rwrap )
68 {
69 GLboolean is_clamp = GL_FALSE;
70 GLboolean is_clamp_to_border = GL_FALSE;
71 struct gl_texture_object *tObj = &t->base;
72
73 t->pp_txfilter &= ~(R200_CLAMP_S_MASK | R200_CLAMP_T_MASK | R200_BORDER_MODE_D3D);
74
75 switch ( swrap ) {
76 case GL_REPEAT:
77 t->pp_txfilter |= R200_CLAMP_S_WRAP;
78 break;
79 case GL_CLAMP:
80 t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
81 is_clamp = GL_TRUE;
82 break;
83 case GL_CLAMP_TO_EDGE:
84 t->pp_txfilter |= R200_CLAMP_S_CLAMP_LAST;
85 break;
86 case GL_CLAMP_TO_BORDER:
87 t->pp_txfilter |= R200_CLAMP_S_CLAMP_GL;
88 is_clamp_to_border = GL_TRUE;
89 break;
90 case GL_MIRRORED_REPEAT:
91 t->pp_txfilter |= R200_CLAMP_S_MIRROR;
92 break;
93 case GL_MIRROR_CLAMP_EXT:
94 t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
95 is_clamp = GL_TRUE;
96 break;
97 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
98 t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_LAST;
99 break;
100 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
101 t->pp_txfilter |= R200_CLAMP_S_MIRROR_CLAMP_GL;
102 is_clamp_to_border = GL_TRUE;
103 break;
104 default:
105 _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__);
106 }
107
108 if (tObj->Target != GL_TEXTURE_1D) {
109 switch ( twrap ) {
110 case GL_REPEAT:
111 t->pp_txfilter |= R200_CLAMP_T_WRAP;
112 break;
113 case GL_CLAMP:
114 t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
115 is_clamp = GL_TRUE;
116 break;
117 case GL_CLAMP_TO_EDGE:
118 t->pp_txfilter |= R200_CLAMP_T_CLAMP_LAST;
119 break;
120 case GL_CLAMP_TO_BORDER:
121 t->pp_txfilter |= R200_CLAMP_T_CLAMP_GL;
122 is_clamp_to_border = GL_TRUE;
123 break;
124 case GL_MIRRORED_REPEAT:
125 t->pp_txfilter |= R200_CLAMP_T_MIRROR;
126 break;
127 case GL_MIRROR_CLAMP_EXT:
128 t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
129 is_clamp = GL_TRUE;
130 break;
131 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
132 t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_LAST;
133 break;
134 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
135 t->pp_txfilter |= R200_CLAMP_T_MIRROR_CLAMP_GL;
136 is_clamp_to_border = GL_TRUE;
137 break;
138 default:
139 _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__);
140 }
141 }
142
143 t->pp_txformat_x &= ~R200_CLAMP_Q_MASK;
144
145 switch ( rwrap ) {
146 case GL_REPEAT:
147 t->pp_txformat_x |= R200_CLAMP_Q_WRAP;
148 break;
149 case GL_CLAMP:
150 t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
151 is_clamp = GL_TRUE;
152 break;
153 case GL_CLAMP_TO_EDGE:
154 t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_LAST;
155 break;
156 case GL_CLAMP_TO_BORDER:
157 t->pp_txformat_x |= R200_CLAMP_Q_CLAMP_GL;
158 is_clamp_to_border = GL_TRUE;
159 break;
160 case GL_MIRRORED_REPEAT:
161 t->pp_txformat_x |= R200_CLAMP_Q_MIRROR;
162 break;
163 case GL_MIRROR_CLAMP_EXT:
164 t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
165 is_clamp = GL_TRUE;
166 break;
167 case GL_MIRROR_CLAMP_TO_EDGE_EXT:
168 t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_LAST;
169 break;
170 case GL_MIRROR_CLAMP_TO_BORDER_EXT:
171 t->pp_txformat_x |= R200_CLAMP_Q_MIRROR_CLAMP_GL;
172 is_clamp_to_border = GL_TRUE;
173 break;
174 default:
175 _mesa_problem(NULL, "bad R wrap mode in %s", __FUNCTION__);
176 }
177
178 if ( is_clamp_to_border ) {
179 t->pp_txfilter |= R200_BORDER_MODE_D3D;
180 }
181
182 t->border_fallback = (is_clamp && is_clamp_to_border);
183 }
184
185 static void r200SetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max )
186 {
187 t->pp_txfilter &= ~R200_MAX_ANISO_MASK;
188
189 if ( max <= 1.0 ) {
190 t->pp_txfilter |= R200_MAX_ANISO_1_TO_1;
191 } else if ( max <= 2.0 ) {
192 t->pp_txfilter |= R200_MAX_ANISO_2_TO_1;
193 } else if ( max <= 4.0 ) {
194 t->pp_txfilter |= R200_MAX_ANISO_4_TO_1;
195 } else if ( max <= 8.0 ) {
196 t->pp_txfilter |= R200_MAX_ANISO_8_TO_1;
197 } else {
198 t->pp_txfilter |= R200_MAX_ANISO_16_TO_1;
199 }
200 }
201
202 /**
203 * Set the texture magnification and minification modes.
204 *
205 * \param t Texture whose filter modes are to be set
206 * \param minf Texture minification mode
207 * \param magf Texture magnification mode
208 */
209
210 static void r200SetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf )
211 {
212 GLuint anisotropy = (t->pp_txfilter & R200_MAX_ANISO_MASK);
213
214 t->pp_txfilter &= ~(R200_MIN_FILTER_MASK | R200_MAG_FILTER_MASK);
215 t->pp_txformat_x &= ~R200_VOLUME_FILTER_MASK;
216
217 if ( anisotropy == R200_MAX_ANISO_1_TO_1 ) {
218 switch ( minf ) {
219 case GL_NEAREST:
220 t->pp_txfilter |= R200_MIN_FILTER_NEAREST;
221 break;
222 case GL_LINEAR:
223 t->pp_txfilter |= R200_MIN_FILTER_LINEAR;
224 break;
225 case GL_NEAREST_MIPMAP_NEAREST:
226 t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_NEAREST;
227 break;
228 case GL_NEAREST_MIPMAP_LINEAR:
229 t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_NEAREST;
230 break;
231 case GL_LINEAR_MIPMAP_NEAREST:
232 t->pp_txfilter |= R200_MIN_FILTER_NEAREST_MIP_LINEAR;
233 break;
234 case GL_LINEAR_MIPMAP_LINEAR:
235 t->pp_txfilter |= R200_MIN_FILTER_LINEAR_MIP_LINEAR;
236 break;
237 }
238 } else {
239 switch ( minf ) {
240 case GL_NEAREST:
241 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST;
242 break;
243 case GL_LINEAR:
244 t->pp_txfilter |= R200_MIN_FILTER_ANISO_LINEAR;
245 break;
246 case GL_NEAREST_MIPMAP_NEAREST:
247 case GL_LINEAR_MIPMAP_NEAREST:
248 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST;
249 break;
250 case GL_NEAREST_MIPMAP_LINEAR:
251 case GL_LINEAR_MIPMAP_LINEAR:
252 t->pp_txfilter |= R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR;
253 break;
254 }
255 }
256
257 /* Note we don't have 3D mipmaps so only use the mag filter setting
258 * to set the 3D texture filter mode.
259 */
260 switch ( magf ) {
261 case GL_NEAREST:
262 t->pp_txfilter |= R200_MAG_FILTER_NEAREST;
263 t->pp_txformat_x |= R200_VOLUME_FILTER_NEAREST;
264 break;
265 case GL_LINEAR:
266 t->pp_txfilter |= R200_MAG_FILTER_LINEAR;
267 t->pp_txformat_x |= R200_VOLUME_FILTER_LINEAR;
268 break;
269 }
270 }
271
272 static void r200SetTexBorderColor( radeonTexObjPtr t, GLubyte c[4] )
273 {
274 t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
275 }
276
277
278
279
280
281 static void r200TexEnv( GLcontext *ctx, GLenum target,
282 GLenum pname, const GLfloat *param )
283 {
284 r200ContextPtr rmesa = R200_CONTEXT(ctx);
285 GLuint unit = ctx->Texture.CurrentUnit;
286 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
287
288 if ( R200_DEBUG & DEBUG_STATE ) {
289 fprintf( stderr, "%s( %s )\n",
290 __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) );
291 }
292
293 /* This is incorrect: Need to maintain this data for each of
294 * GL_TEXTURE_{123}D, GL_TEXTURE_RECTANGLE_NV, etc, and switch
295 * between them according to _ReallyEnabled.
296 */
297 switch ( pname ) {
298 case GL_TEXTURE_ENV_COLOR: {
299 GLubyte c[4];
300 GLuint envColor;
301 UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor );
302 envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] );
303 if ( rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] != envColor ) {
304 R200_STATECHANGE( rmesa, tf );
305 rmesa->hw.tf.cmd[TF_TFACTOR_0 + unit] = envColor;
306 }
307 break;
308 }
309
310 case GL_TEXTURE_LOD_BIAS_EXT: {
311 GLfloat bias, min;
312 GLuint b;
313 const int fixed_one = 0x8000000;
314
315 /* The R200's LOD bias is a signed 2's complement value with a
316 * range of -16.0 <= bias < 16.0.
317 *
318 * NOTE: Add a small bias to the bias for conform mipsel.c test.
319 */
320 bias = *param + .01;
321 min = driQueryOptionb (&rmesa->radeon.optionCache, "no_neg_lod_bias") ?
322 0.0 : -16.0;
323 bias = CLAMP( bias, min, 16.0 );
324 b = (int)(bias * fixed_one) & R200_LOD_BIAS_MASK;
325
326 if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] & R200_LOD_BIAS_MASK) != b ) {
327 R200_STATECHANGE( rmesa, tex[unit] );
328 rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] &= ~R200_LOD_BIAS_MASK;
329 rmesa->hw.tex[unit].cmd[TEX_PP_TXFORMAT_X] |= b;
330 }
331 break;
332 }
333 case GL_COORD_REPLACE_ARB:
334 if (ctx->Point.PointSprite) {
335 R200_STATECHANGE( rmesa, spr );
336 if ((GLenum)param[0]) {
337 rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] |= R200_PS_GEN_TEX_0 << unit;
338 } else {
339 rmesa->hw.spr.cmd[SPR_POINT_SPRITE_CNTL] &= ~(R200_PS_GEN_TEX_0 << unit);
340 }
341 }
342 break;
343 default:
344 return;
345 }
346 }
347
348
349 /**
350 * Changes variables and flags for a state update, which will happen at the
351 * next UpdateTextureState
352 */
353
354 static void r200TexParameter( GLcontext *ctx, GLenum target,
355 struct gl_texture_object *texObj,
356 GLenum pname, const GLfloat *params )
357 {
358 radeonTexObj* t = radeon_tex_obj(texObj);
359
360 if ( R200_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) {
361 fprintf( stderr, "%s( %s )\n", __FUNCTION__,
362 _mesa_lookup_enum_by_nr( pname ) );
363 }
364
365 switch ( pname ) {
366 case GL_TEXTURE_MIN_FILTER:
367 case GL_TEXTURE_MAG_FILTER:
368 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
369 r200SetTexMaxAnisotropy( t, texObj->MaxAnisotropy );
370 r200SetTexFilter( t, texObj->MinFilter, texObj->MagFilter );
371 break;
372
373 case GL_TEXTURE_WRAP_S:
374 case GL_TEXTURE_WRAP_T:
375 case GL_TEXTURE_WRAP_R:
376 r200SetTexWrap( t, texObj->WrapS, texObj->WrapT, texObj->WrapR );
377 break;
378
379 case GL_TEXTURE_BORDER_COLOR:
380 r200SetTexBorderColor( t, texObj->_BorderChan );
381 break;
382
383 case GL_TEXTURE_BASE_LEVEL:
384 case GL_TEXTURE_MAX_LEVEL:
385 case GL_TEXTURE_MIN_LOD:
386 case GL_TEXTURE_MAX_LOD:
387 /* This isn't the most efficient solution but there doesn't appear to
388 * be a nice alternative. Since there's no LOD clamping,
389 * we just have to rely on loading the right subset of mipmap levels
390 * to simulate a clamped LOD.
391 */
392 driSwapOutTextureObject( (driTextureObject *) t );
393 break;
394
395 default:
396 return;
397 }
398
399 /* Mark this texobj as dirty (one bit per tex unit)
400 */
401 t->dirty_state = R200_TEX_ALL;
402 }
403
404
405 static void r200DeleteTexture(GLcontext * ctx, struct gl_texture_object *texObj)
406 {
407 r200ContextPtr rmesa = R200_CONTEXT(ctx);
408 radeonTexObj* t = radeon_tex_obj(texObj);
409
410 if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) {
411 fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__,
412 (void *)texObj,
413 _mesa_lookup_enum_by_nr(texObj->Target));
414 }
415
416 if (rmesa) {
417 int i;
418 R200_FIREVERTICES(rmesa);
419 for ( i = 0 ; i < rmesa->radeon.glCtx->Const.MaxTextureUnits ; i++ ) {
420 if ( t == rmesa->state.texture.unit[i].texobj ) {
421 rmesa->state.texture.unit[i].texobj = NULL;
422 rmesa->hw.tex[i].dirty = GL_FALSE;
423 rmesa->hw.cube[i].dirty = GL_FALSE;
424 }
425 }
426 }
427
428 if (t->mt) {
429 radeon_miptree_unreference(t->mt);
430 t->mt = 0;
431 }
432 _mesa_delete_texture_object(ctx, texObj);
433 }
434
435 /* Need:
436 * - Same GEN_MODE for all active bits
437 * - Same EyePlane/ObjPlane for all active bits when using Eye/Obj
438 * - STRQ presumably all supported (matrix means incoming R values
439 * can end up in STQ, this has implications for vertex support,
440 * presumably ok if maos is used, though?)
441 *
442 * Basically impossible to do this on the fly - just collect some
443 * basic info & do the checks from ValidateState().
444 */
445 static void r200TexGen( GLcontext *ctx,
446 GLenum coord,
447 GLenum pname,
448 const GLfloat *params )
449 {
450 r200ContextPtr rmesa = R200_CONTEXT(ctx);
451 GLuint unit = ctx->Texture.CurrentUnit;
452 rmesa->recheck_texgen[unit] = GL_TRUE;
453 }
454
455
456 /**
457 * Allocate a new texture object.
458 * Called via ctx->Driver.NewTextureObject.
459 * Note: this function will be called during context creation to
460 * allocate the default texture objects.
461 * Fixup MaxAnisotropy according to user preference.
462 */
463 static struct gl_texture_object *r200NewTextureObject(GLcontext * ctx,
464 GLuint name,
465 GLenum target)
466 {
467 r200ContextPtr rmesa = R200_CONTEXT(ctx);
468 radeonTexObj* t = CALLOC_STRUCT(radeon_tex_obj);
469
470
471 if (RADEON_DEBUG & (DEBUG_STATE | DEBUG_TEXTURE)) {
472 fprintf(stderr, "%s( %p (target = %s) )\n", __FUNCTION__,
473 t, _mesa_lookup_enum_by_nr(target));
474 }
475
476 _mesa_initialize_texture_object(&t->base, name, target);
477 t->base.MaxAnisotropy = rmesa->radeon.initialMaxAnisotropy;
478
479 /* Initialize hardware state */
480 r200SetTexWrap( t, t->base.WrapS, t->base.WrapT, t->base.WrapR );
481 r200SetTexMaxAnisotropy( t, t->base.MaxAnisotropy );
482 r200SetTexFilter(t, t->base.MinFilter, t->base.MagFilter);
483 r200SetTexBorderColor(t, t->base._BorderChan);
484
485 return &t->base;
486 }
487
488
489
490 void r200InitTextureFuncs( struct dd_function_table *functions )
491 {
492 /* Note: we only plug in the functions we implement in the driver
493 * since _mesa_init_driver_functions() was already called.
494 */
495 functions->ChooseTextureFormat = radeonChooseTextureFormat;
496 functions->TexImage1D = radeonTexImage1D;
497 functions->TexImage2D = radeonTexImage2D;
498 #if ENABLE_HW_3D_TEXTURE
499 functions->TexImage3D = radeonTexImage3D;
500 #else
501 functions->TexImage3D = _mesa_store_teximage3d;
502 #endif
503 functions->TexSubImage1D = radeonTexSubImage1D;
504 functions->TexSubImage2D = radeonTexSubImage2D;
505 #if ENABLE_HW_3D_TEXTURE
506 functions->TexSubImage3D = radeonTexSubImage3D;
507 #else
508 functions->TexSubImage3D = _mesa_store_texsubimage3d;
509 #endif
510 functions->NewTextureObject = r200NewTextureObject;
511 // functions->BindTexture = r200BindTexture;
512 functions->DeleteTexture = r200DeleteTexture;
513 functions->IsTextureResident = driIsTextureResident;
514
515 functions->TexEnv = r200TexEnv;
516 functions->TexParameter = r200TexParameter;
517 functions->TexGen = r200TexGen;
518
519 functions->CompressedTexImage2D = radeonCompressedTexImage2D;
520 functions->CompressedTexSubImage2D = radeonCompressedTexSubImage2D;
521
522 functions->GenerateMipmap = radeon_generate_mipmap;
523
524 functions->NewTextureImage = radeonNewTextureImage;
525 functions->FreeTexImageData = radeonFreeTexImageData;
526 functions->MapTexture = radeonMapTexture;
527 functions->UnmapTexture = radeonUnmapTexture;
528
529 driInitTextureFormats();
530
531 }