2 * Copyright 2000-2001 VA Linux Systems, Inc.
3 * (c) Copyright IBM Corporation 2002
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * on the rights to use, copy, modify, merge, publish, distribute, sub
10 * license, and/or sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * VA LINUX SYSTEMS, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Ian Romanick <idr@us.ibm.com>
27 * Keith Whitwell <keithw@tungstengraphics.com>
32 #include "mgacontext.h"
43 #include "simple_list.h"
44 #include "texformat.h"
46 #define MGA_USE_TABLE_FOR_FORMAT
47 #ifdef MGA_USE_TABLE_FOR_FORMAT
48 #define TMC_nr_tformat (MESA_FORMAT_YCBCR_REV + 1)
49 static const unsigned TMC_tformat
[ TMC_nr_tformat
] =
51 [MESA_FORMAT_ARGB8888
] = TMC_tformat_tw32
| TMC_takey_1
| TMC_tamask_0
,
52 [MESA_FORMAT_RGB565
] = TMC_tformat_tw16
| TMC_takey_1
| TMC_tamask_0
,
53 [MESA_FORMAT_ARGB4444
] = TMC_tformat_tw12
| TMC_takey_1
| TMC_tamask_0
,
54 [MESA_FORMAT_ARGB1555
] = TMC_tformat_tw15
| TMC_takey_1
| TMC_tamask_0
,
55 [MESA_FORMAT_CI8
] = TMC_tformat_tw8
| TMC_takey_1
| TMC_tamask_0
,
56 [MESA_FORMAT_YCBCR
] = TMC_tformat_tw422uyvy
| TMC_takey_1
| TMC_tamask_0
,
57 [MESA_FORMAT_YCBCR_REV
] = TMC_tformat_tw422
| TMC_takey_1
| TMC_tamask_0
,
62 mgaSetTexImages( mgaContextPtr mmesa
,
63 const struct gl_texture_object
* tObj
)
65 mgaTextureObjectPtr t
= (mgaTextureObjectPtr
) tObj
->DriverData
;
66 struct gl_texture_image
*baseImage
= tObj
->Image
[ tObj
->BaseLevel
];
70 GLint firstLevel
, lastLevel
, numLevels
;
71 GLint log2Width
, log2Height
;
75 /* Set the hardware texture format
77 #ifndef MGA_USE_TABLE_FOR_FORMAT
78 switch (baseImage
->TexFormat
->MesaFormat
) {
80 case MESA_FORMAT_ARGB8888
: txformat
= TMC_tformat_tw32
; break;
81 case MESA_FORMAT_RGB565
: txformat
= TMC_tformat_tw16
; break;
82 case MESA_FORMAT_ARGB4444
: txformat
= TMC_tformat_tw12
; break;
83 case MESA_FORMAT_ARGB1555
: txformat
= TMC_tformat_tw15
; break;
84 case MESA_FORMAT_CI8
: txformat
= TMC_tformat_tw8
; break;
85 case MESA_FORMAT_YCBCR
: txformat
= TMC_tformat_tw422uyvy
; break;
86 case MESA_FORMAT_YCBCR_REV
: txformat
= TMC_tformat_tw422
; break;
89 _mesa_problem(NULL
, "unexpected texture format in %s", __FUNCTION__
);
93 if ( (baseImage
->TexFormat
->MesaFormat
>= TMC_nr_tformat
)
94 || (TMC_tformat
[ baseImage
->TexFormat
->MesaFormat
] == 0) )
96 _mesa_problem(NULL
, "unexpected texture format in %s", __FUNCTION__
);
100 txformat
= TMC_tformat
[ baseImage
->TexFormat
->MesaFormat
];
102 #endif /* MGA_USE_TABLE_FOR_FORMAT */
104 if (tObj
->MinFilter
== GL_NEAREST
|| tObj
->MinFilter
== GL_LINEAR
) {
105 /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
108 firstLevel
= lastLevel
= tObj
->BaseLevel
;
110 /* Compute which mipmap levels we really want to send to the hardware.
111 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
112 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
113 * Yes, this looks overly complicated, but it's all needed.
116 firstLevel
= tObj
->BaseLevel
+ (GLint
)(tObj
->MinLod
+ 0.5);
117 firstLevel
= MAX2(firstLevel
, tObj
->BaseLevel
);
118 lastLevel
= tObj
->BaseLevel
+ (GLint
)(tObj
->MaxLod
+ 0.5);
119 lastLevel
= MAX2(lastLevel
, tObj
->BaseLevel
);
120 lastLevel
= MIN2(lastLevel
, tObj
->BaseLevel
+ baseImage
->MaxLog2
);
121 lastLevel
= MIN2(lastLevel
, tObj
->MaxLevel
);
122 lastLevel
= MAX2(firstLevel
, lastLevel
); /* need at least one level */
125 log2Width
= tObj
->Image
[firstLevel
]->WidthLog2
;
126 log2Height
= tObj
->Image
[firstLevel
]->HeightLog2
;
127 width
= tObj
->Image
[firstLevel
]->Width
;
128 height
= tObj
->Image
[firstLevel
]->Height
;
130 numLevels
= MIN2( lastLevel
- firstLevel
+ 1,
131 MGA_IS_G200(mmesa
) ? G200_TEX_MAXLEVELS
: G400_TEX_MAXLEVELS
);
135 for ( i
= 0 ; i
< numLevels
; i
++ ) {
136 const struct gl_texture_image
* const texImage
= tObj
->Image
[i
+firstLevel
];
138 if ( (texImage
== NULL
)
140 && ((texImage
->Width
< 8) || (texImage
->Height
< 8))) ) {
144 t
->offsets
[i
] = totalSize
;
145 t
->base
.dirty_images
[0] |= (1<<i
);
147 totalSize
+= ((MAX2( texImage
->Width
, 8 ) *
148 MAX2( texImage
->Height
, 8 ) *
149 baseImage
->TexFormat
->TexelBytes
) + 31) & ~31;
153 lastLevel
= firstLevel
+ numLevels
- 1;
155 /* save these values */
156 t
->base
.firstLevel
= firstLevel
;
157 t
->base
.lastLevel
= lastLevel
;
159 t
->base
.totalSize
= totalSize
;
161 /* setup hardware register values */
162 t
->setup
.texctl
&= (TMC_tformat_MASK
& TMC_tpitch_MASK
163 & TMC_tpitchext_MASK
);
164 t
->setup
.texctl
|= txformat
;
167 /* Set the texture width. In order to support non-power of 2 textures and
168 * textures larger than 1024 texels wide, "linear" pitch must be used. For
169 * the linear pitch, if the width is 2048, a value of zero is used.
172 t
->setup
.texctl
|= TMC_tpitchlin_enable
;
173 t
->setup
.texctl
|= (width
& (2048 - 1)) << TMC_tpitchext_SHIFT
;
176 /* G400 specifies the number of mip levels in a strange way. Since there
177 * are up to 12 levels, it requires 4 bits. Three of the bits are at the
178 * high end of TEXFILTER. The other bit is in the middle. Weird.
181 t
->setup
.texfilter
&= TF_mapnb_MASK
& TF_mapnbhigh_MASK
& TF_reserved_MASK
;
182 t
->setup
.texfilter
|= (((numLevels
-1) & 0x07) << (TF_mapnb_SHIFT
));
183 t
->setup
.texfilter
|= (((numLevels
-1) & 0x08) << (TF_mapnbhigh_SHIFT
- 3));
185 /* warp texture registers */
186 ofs
= MGA_IS_G200(mmesa
) ? 28 : 11;
188 t
->setup
.texwidth
= (MGA_FIELD(TW_twmask
, width
- 1) |
189 MGA_FIELD(TW_rfw
, (10 - log2Width
- 8) & 63 ) |
190 MGA_FIELD(TW_tw
, (log2Width
+ ofs
) | 0x40 ));
192 t
->setup
.texheight
= (MGA_FIELD(TH_thmask
, height
- 1) |
193 MGA_FIELD(TH_rfh
, (10 - log2Height
- 8) & 63 ) |
194 MGA_FIELD(TH_th
, (log2Height
+ ofs
) | 0x40 ));
196 mgaUploadTexImages( mmesa
, t
);
200 /* ================================================================
201 * Texture unit state management
204 static void mgaUpdateTextureEnvG200( GLcontext
*ctx
, GLuint unit
)
206 struct gl_texture_object
*tObj
= ctx
->Texture
.Unit
[0]._Current
;
207 mgaTextureObjectPtr t
;
209 if (!tObj
|| !tObj
->DriverData
)
212 t
= (mgaTextureObjectPtr
)tObj
->DriverData
;
214 t
->setup
.texctl2
&= ~TMC_decalblend_enable
;
216 switch (ctx
->Texture
.Unit
[0].EnvMode
) {
218 t
->setup
.texctl
&= ~TMC_tmodulate_enable
;
221 t
->setup
.texctl
|= TMC_tmodulate_enable
;
224 t
->setup
.texctl
&= ~TMC_tmodulate_enable
;
225 t
->setup
.texctl2
|= TMC_decalblend_enable
;
228 FALLBACK( ctx
, MGA_FALLBACK_TEXTURE
, GL_TRUE
);
236 #define MGA_DISABLE 0
237 #define MGA_REPLACE 1
238 #define MGA_MODULATE 2
242 #define MGA_MAX_COMBFUNC 6
244 static const GLuint g400_color_combine
[][MGA_MAX_COMBFUNC
] =
249 /* Disable combiner stage
255 (TD0_color_sel_arg1
|
256 TD0_alpha_arg2_diffuse
|
257 TD0_alpha_sel_arg2
),
261 (TD0_color_arg2_diffuse
|
263 TD0_alpha_arg2_diffuse
|
268 (TD0_color_sel_arg1
|
269 TD0_alpha_arg2_diffuse
|
278 (TD0_color_arg2_diffuse
|
281 TD0_alpha_arg2_diffuse
|
288 /* Disable combiner stage
294 (TD0_color_sel_arg1
|
295 TD0_alpha_arg2_diffuse
|
296 TD0_alpha_sel_arg2
),
300 (TD0_color_arg2_prevstage
|
301 TD0_color_alpha_prevstage
|
303 TD0_alpha_arg2_prevstage
|
308 (TD0_color_sel_arg1
|
309 TD0_alpha_arg2_prevstage
|
310 TD0_alpha_sel_arg2
),
318 (TD0_color_arg2_prevstage
|
319 TD0_color_alpha_prevstage
|
322 TD0_alpha_arg2_prevstage
|
327 static const GLuint g400_alpha_combine
[][MGA_MAX_COMBFUNC
] =
332 /* Disable combiner stage
338 (TD0_color_sel_arg2
|
339 TD0_color_arg2_diffuse
|
340 TD0_alpha_sel_arg1
),
343 * FIXME: Is this correct?
345 (TD0_color_arg2_diffuse
|
347 TD0_alpha_arg2_diffuse
|
352 (TD0_color_arg2_diffuse
|
354 TD0_alpha_arg2_diffuse
|
359 (TD0_color_arg2_diffuse
|
361 TD0_alpha_arg2_diffuse
|
366 (TD0_color_arg2_diffuse
|
368 TD0_alpha_arg2_diffuse
|
375 /* Disable combiner stage
381 (TD0_color_sel_arg2
|
382 TD0_color_arg2_diffuse
|
383 TD0_alpha_sel_arg1
),
386 * FIXME: Is this correct?
388 (TD0_color_arg2_prevstage
|
389 TD0_color_alpha_prevstage
|
391 TD0_alpha_arg2_prevstage
|
396 (TD0_color_arg2_prevstage
|
398 TD0_alpha_arg2_prevstage
|
403 (TD0_color_arg2_diffuse
|
405 TD0_alpha_arg2_diffuse
|
410 (TD0_color_arg2_prevstage
|
412 TD0_alpha_arg2_prevstage
|
417 static void mgaUpdateTextureEnvG400( GLcontext
*ctx
, GLuint unit
)
419 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
420 const int source
= mmesa
->tmu_source
[unit
];
421 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
422 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
423 GLuint
*reg
= ((GLuint
*)&mmesa
->setup
.tdualstage0
+ unit
);
426 if ( tObj
!= ctx
->Texture
.Unit
[source
].Current2D
|| !tObj
)
429 format
= tObj
->Image
[tObj
->BaseLevel
]->Format
;
431 switch (ctx
->Texture
.Unit
[source
].EnvMode
) {
433 if (format
== GL_RGB
|| format
== GL_LUMINANCE
) {
434 *reg
= g400_color_combine
[unit
][MGA_REPLACE
];
436 else if (format
== GL_ALPHA
) {
437 *reg
= g400_alpha_combine
[unit
][MGA_REPLACE
];
440 *reg
= (TD0_color_sel_arg1
|
441 TD0_alpha_sel_arg1
);
446 *reg
= g400_color_combine
[unit
][MGA_MODULATE
];
449 if (format
== GL_RGB
) {
450 *reg
= g400_color_combine
[unit
][MGA_DECAL
];
452 else if ( format
== GL_RGBA
) {
455 /* this doesn't work */
456 *reg
= (TD0_color_arg2_diffuse
|
457 TD0_color_alpha_currtex
|
458 TD0_color_alpha2inv_enable
|
459 TD0_color_arg2mul_alpha2
|
460 TD0_color_arg1mul_alpha1
|
461 TD0_color_blend_enable
|
462 TD0_color_arg1add_mulout
|
463 TD0_color_arg2add_mulout
|
466 TD0_alpha_arg2_diffuse
|
467 TD0_alpha_sel_arg2
);
470 *reg
= (TD0_color_arg2_prevstage
|
471 TD0_color_alpha_currtex
|
472 TD0_color_alpha2inv_enable
|
473 TD0_color_arg2mul_alpha2
|
474 TD0_color_arg1mul_alpha1
|
477 TD0_alpha_arg2_prevstage
|
478 TD0_alpha_sel_arg2
);
481 /* s/w fallback, pretty sure we can't do in h/w */
482 FALLBACK( ctx
, MGA_FALLBACK_TEXTURE
, GL_TRUE
);
483 if ( MGA_DEBUG
& DEBUG_VERBOSE_FALLBACK
)
484 fprintf( stderr
, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n",
489 *reg
= g400_alpha_combine
[unit
][MGA_DECAL
];
494 if (format
== GL_INTENSITY
) {
496 *reg
= ( TD0_color_arg2_diffuse
|
499 TD0_alpha_arg2_diffuse
|
500 TD0_alpha_add_enable
|
504 *reg
= ( TD0_color_arg2_prevstage
|
507 TD0_alpha_arg2_prevstage
|
508 TD0_alpha_add_enable
|
512 else if (format
== GL_ALPHA
) {
513 *reg
= g400_alpha_combine
[unit
][MGA_ADD
];
516 *reg
= g400_color_combine
[unit
][MGA_ADD
];
521 if (format
== GL_ALPHA
) {
522 *reg
= g400_alpha_combine
[unit
][MGA_BLEND
];
525 FALLBACK( ctx
, MGA_FALLBACK_TEXTURE
, GL_TRUE
);
526 if ( MGA_DEBUG
& DEBUG_VERBOSE_FALLBACK
)
527 fprintf( stderr
, "FALLBACK: GL_BLEND envcolor=0x%08x\n",
530 /* Do singletexture GL_BLEND with 'all ones' env-color
531 * by using both texture units. Multitexture gl_blend
535 /* Part 1: R1 = Rf ( 1 - Rt )
538 *reg
= ( TD0_color_arg2_diffuse
|
539 TD0_color_arg1_inv_enable
|
541 TD0_alpha_arg2_diffuse
|
544 /* Part 2: R2 = R1 + Rt
547 *reg
= ( TD0_color_arg2_prevstage
|
550 TD0_alpha_arg2_prevstage
|
561 static void disable_tex( GLcontext
*ctx
, int unit
)
563 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
565 /* Texture unit disabled */
567 if ( mmesa
->CurrentTexObj
[unit
] != NULL
) {
568 /* The old texture is no longer bound to this texture unit.
572 mmesa
->CurrentTexObj
[unit
]->base
.bound
&= ~(1UL << unit
);
573 mmesa
->CurrentTexObj
[unit
] = NULL
;
577 mmesa
->setup
.tdualstage1
= mmesa
->setup
.tdualstage0
;
580 if ( ctx
->Texture
._EnabledUnits
== 0 ) {
581 mmesa
->setup
.dwgctl
&= DC_opcod_MASK
;
582 mmesa
->setup
.dwgctl
|= DC_opcod_trap
;
583 mmesa
->hw
.alpha_sel
= AC_alphasel_diffused
;
586 mmesa
->dirty
|= MGA_UPLOAD_CONTEXT
| (MGA_UPLOAD_TEX0
<< unit
);
589 static GLboolean
enable_tex_2d( GLcontext
*ctx
, int unit
)
591 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
592 const int source
= mmesa
->tmu_source
[unit
];
593 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
594 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
595 mgaTextureObjectPtr t
= (mgaTextureObjectPtr
) tObj
->DriverData
;
597 /* Upload teximages (not pipelined)
599 if (t
->base
.dirty_images
[0]) {
600 FLUSH_BATCH( mmesa
);
601 mgaSetTexImages( mmesa
, tObj
);
602 if ( t
->base
.memBlock
== NULL
) {
610 static GLboolean
update_tex_common( GLcontext
*ctx
, int unit
)
612 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
613 const int source
= mmesa
->tmu_source
[unit
];
614 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
615 struct gl_texture_object
*tObj
= texUnit
->_Current
;
616 mgaTextureObjectPtr t
= (mgaTextureObjectPtr
) tObj
->DriverData
;
618 /* Fallback if there's a texture border */
619 if ( tObj
->Image
[tObj
->BaseLevel
]->Border
> 0 ) {
624 /* Update state if this is a different texture object to last
627 if ( mmesa
->CurrentTexObj
[unit
] != t
) {
628 if ( mmesa
->CurrentTexObj
[unit
] != NULL
) {
629 /* The old texture is no longer bound to this texture unit.
633 mmesa
->CurrentTexObj
[unit
]->base
.bound
&= ~(1UL << unit
);
636 mmesa
->CurrentTexObj
[unit
] = t
;
637 t
->base
.bound
|= (1UL << unit
);
639 driUpdateTextureLRU( (driTextureObject
*) t
); /* done too often */
644 mmesa
->setup
.tdualstage1
= mmesa
->setup
.tdualstage0
;
647 t
->setup
.texctl2
&= TMC_dualtex_MASK
;
648 if (ctx
->Texture
._EnabledUnits
== 0x03) {
649 t
->setup
.texctl2
|= TMC_dualtex_enable
;
652 /* FIXME: The Radeon has some cached state so that it can avoid calling
653 * FIXME: UpdateTextureEnv in some cases. Is that possible here?
655 if (MGA_IS_G400(mmesa
)) {
656 /* G400: Regardless of texture env mode, we use the alpha from the
657 * texture unit (AC_alphasel_fromtex) since it will have already
658 * been modulated by the incoming fragment color, if needed.
659 * We don't want (AC_alphasel_modulate) since that'll effectively
660 * do the modulation twice.
662 mmesa
->hw
.alpha_sel
= AC_alphasel_fromtex
;
664 mgaUpdateTextureEnvG400( ctx
, unit
);
666 mmesa
->hw
.alpha_sel
= 0;
667 switch (ctx
->Texture
.Unit
[0].EnvMode
) {
669 mmesa
->hw
.alpha_sel
|= AC_alphasel_diffused
;
671 mmesa
->hw
.alpha_sel
|= AC_alphasel_fromtex
;
675 mmesa
->hw
.alpha_sel
|= AC_alphasel_modulated
;
681 mgaUpdateTextureEnvG200( ctx
, unit
);
684 mmesa
->setup
.dwgctl
&= DC_opcod_MASK
;
685 mmesa
->setup
.dwgctl
|= DC_opcod_texture_trap
;
686 mmesa
->dirty
|= MGA_UPLOAD_CONTEXT
| (MGA_UPLOAD_TEX0
<< unit
);
688 FALLBACK( ctx
, MGA_FALLBACK_BORDER_MODE
, t
->border_fallback
);
689 return !t
->border_fallback
;
693 static GLboolean
updateTextureUnit( GLcontext
*ctx
, int unit
)
695 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
696 const int source
= mmesa
->tmu_source
[unit
];
697 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
700 if ( texUnit
->_ReallyEnabled
== TEXTURE_2D_BIT
) {
701 return(enable_tex_2d( ctx
, unit
) &&
702 update_tex_common( ctx
, unit
));
704 else if ( texUnit
->_ReallyEnabled
) {
708 disable_tex( ctx
, unit
);
713 /* The G400 is now programmed quite differently wrt texture environment.
715 void mgaUpdateTextureState( GLcontext
*ctx
)
717 mgaContextPtr mmesa
= MGA_CONTEXT( ctx
);
722 /* This works around a quirk with the MGA hardware. If only OpenGL
723 * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The
724 * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used.
727 mmesa
->tmu_source
[0] = 0;
728 mmesa
->tmu_source
[1] = 1;
730 if ((ctx
->Texture
._EnabledUnits
& 0x03) == 0x02) {
731 /* only texture 1 enabled */
732 mmesa
->tmu_source
[0] = 1;
733 mmesa
->tmu_source
[1] = 0;
736 for ( i
= 0, ok
= GL_TRUE
737 ; (i
< ctx
->Const
.MaxTextureUnits
) && ok
739 ok
= updateTextureUnit( ctx
, i
);
742 FALLBACK( ctx
, MGA_FALLBACK_TEXTURE
, !ok
);
744 /* FIXME: I believe that ChooseVertexState should be called here instead of
745 * FIXME: in mgaDDValidateState.