1 /**************************************************************************
3 Copyright 2001 2d3d Inc., Delray Beach, FL
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
28 /* $XFree86: xc/lib/GL/mesa/src/drv/i830/i830_texstate.c,v 1.3 2002/12/10 01:26:53 dawes Exp $ */
31 * \file i830_texstate.c
33 * Heavily based on the I810 driver, which was written by Keith Whitwell.
35 * \author Jeff Hartmann <jhartmann@2d3d.com>
36 * \author Keith Whitwell <keithw@tungstengraphics.com>
42 #include "simple_list.h"
44 #include "texformat.h"
49 #include "i830_screen.h"
52 #include "i830_context.h"
54 #include "i830_state.h"
55 #include "i830_ioctl.h"
57 #define I830_TEX_UNIT_ENABLED(unit) (1<<unit)
59 static void i830SetTexImages( i830ContextPtr imesa
,
60 struct gl_texture_object
*tObj
)
62 GLuint total_height
, pitch
, i
, textureFormat
;
63 i830TextureObjectPtr t
= (i830TextureObjectPtr
) tObj
->DriverData
;
64 const struct gl_texture_image
*baseImage
= tObj
->Image
[0][tObj
->BaseLevel
];
67 switch( baseImage
->TexFormat
->MesaFormat
) {
70 textureFormat
= MAPSURF_8BIT
| MT_8BIT_L8
;
75 textureFormat
= MAPSURF_8BIT
| MT_8BIT_I8
;
78 case MESA_FORMAT_AL88
:
80 textureFormat
= MAPSURF_16BIT
| MT_16BIT_AY88
;
83 case MESA_FORMAT_RGB565
:
85 textureFormat
= MAPSURF_16BIT
| MT_16BIT_RGB565
;
88 case MESA_FORMAT_ARGB1555
:
90 textureFormat
= MAPSURF_16BIT
| MT_16BIT_ARGB1555
;
93 case MESA_FORMAT_ARGB4444
:
95 textureFormat
= MAPSURF_16BIT
| MT_16BIT_ARGB4444
;
98 case MESA_FORMAT_ARGB8888
:
100 textureFormat
= MAPSURF_32BIT
| MT_32BIT_ARGB8888
;
103 case MESA_FORMAT_YCBCR_REV
:
105 textureFormat
= (MAPSURF_422
| MT_422_YCRCB_NORMAL
|
106 TM0S1_COLORSPACE_CONVERSION
);
109 case MESA_FORMAT_YCBCR
:
111 textureFormat
= (MAPSURF_422
| MT_422_YCRCB_SWAPY
| /* ??? */
112 TM0S1_COLORSPACE_CONVERSION
);
116 fprintf(stderr
, "%s: bad image format\n", __FUNCTION__
);
121 /* Compute which mipmap levels we really want to send to the hardware.
124 driCalculateTextureFirstLastLevel( (driTextureObject
*) t
);
127 /* Figure out the amount of memory required to hold all the mipmap
128 * levels. Choose the smallest pitch to accomodate the largest
131 numLevels
= t
->base
.lastLevel
- t
->base
.firstLevel
+ 1;
133 /* Pitch would be subject to additional rules if texture memory were
134 * tiled. Currently it isn't.
138 while (pitch
< tObj
->Image
[0][t
->base
.firstLevel
]->Width
* t
->texelBytes
)
142 pitch
= tObj
->Image
[0][t
->base
.firstLevel
]->Width
* t
->texelBytes
;
143 pitch
= (pitch
+ 3) & ~3;
147 /* All images must be loaded at this pitch. Count the number of
150 for ( total_height
= i
= 0 ; i
< numLevels
; i
++ ) {
151 t
->image
[0][i
].image
= tObj
->Image
[0][t
->base
.firstLevel
+ i
];
152 if (!t
->image
[0][i
].image
)
155 t
->image
[0][i
].offset
= total_height
* pitch
;
156 t
->image
[0][i
].internalFormat
= baseImage
->Format
;
157 total_height
+= t
->image
[0][i
].image
->Height
;
161 t
->base
.totalSize
= total_height
*pitch
;
162 t
->Setup
[I830_TEXREG_TM0S1
] =
163 (((tObj
->Image
[0][t
->base
.firstLevel
]->Height
- 1) << TM0S1_HEIGHT_SHIFT
) |
164 ((tObj
->Image
[0][t
->base
.firstLevel
]->Width
- 1) << TM0S1_WIDTH_SHIFT
) |
166 t
->Setup
[I830_TEXREG_TM0S2
] =
167 ((((pitch
/ 4) - 1) << TM0S2_PITCH_SHIFT
));
168 t
->Setup
[I830_TEXREG_TM0S3
] &= ~TM0S3_MAX_MIP_MASK
;
169 t
->Setup
[I830_TEXREG_TM0S3
] &= ~TM0S3_MIN_MIP_MASK
;
170 t
->Setup
[I830_TEXREG_TM0S3
] |= ((numLevels
- 1)*4) << TM0S3_MIN_MIP_SHIFT
;
171 t
->dirty
= I830_UPLOAD_TEX0
| I830_UPLOAD_TEX1
172 | I830_UPLOAD_TEX2
| I830_UPLOAD_TEX3
;
174 LOCK_HARDWARE( imesa
);
175 i830UploadTexImagesLocked( imesa
, t
);
176 UNLOCK_HARDWARE( imesa
);
179 /* ================================================================
180 * Texture combine functions
185 * Calculate the hardware instuctions to setup the current texture enviromnemt
186 * settings. Since \c gl_texture_unit::_CurrentCombine is used, both
187 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture
188 * environments are treated identically.
191 * This function should return \c GLboolean. When \c GL_FALSE is returned,
192 * it means that an environment is selected that the hardware cannot do. This
193 * is the way the Radeon and R200 drivers work.
196 * Looking at i830_3d_regs.h, it seems the i830 can do part of
197 * GL_ATI_texture_env_combine3. It can handle using \c GL_ONE and
198 * \c GL_ZERO as combine inputs (which the code already supports). It can
199 * also handle the \c GL_MODULATE_ADD_ATI mode. Is it worth investigating
200 * partial support for the extension?
203 * Some thought needs to be put into the way combiners work. The driver
204 * treats the hardware as if there's a specific combine unit tied to each
205 * texture unit. That's why there's the special case for a disabled texture
206 * unit. That's not the way the hardware works. In reality, there are 4
207 * texture units and four general instruction slots. Each instruction slot
208 * can use any texture as an input. There's no need for this wierd "no-op"
209 * stuff. If texture units 0 and 3 are enabled, the instructions to combine
210 * them should be in slots 0 and 1, not 0 and 3 with two no-ops inbetween.
213 static void i830UpdateTexEnv( GLcontext
*ctx
, GLuint unit
)
215 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
216 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
217 const GLuint numColorArgs
= texUnit
->_CurrentCombine
->_NumArgsRGB
;
218 const GLuint numAlphaArgs
= texUnit
->_CurrentCombine
->_NumArgsA
;
220 GLboolean need_constant_color
= GL_FALSE
;
225 GLuint rgb_shift
= texUnit
->Combine
.ScaleShiftRGB
;
226 GLuint alpha_shift
= texUnit
->Combine
.ScaleShiftA
;
229 static const GLuint tex_blend_rgb
[3] = {
230 TEXPIPE_COLOR
| TEXBLEND_ARG1
| TEXBLENDARG_MODIFY_PARMS
,
231 TEXPIPE_COLOR
| TEXBLEND_ARG2
| TEXBLENDARG_MODIFY_PARMS
,
232 TEXPIPE_COLOR
| TEXBLEND_ARG0
| TEXBLENDARG_MODIFY_PARMS
,
234 static const GLuint tex_blend_a
[3] = {
235 TEXPIPE_ALPHA
| TEXBLEND_ARG1
| TEXBLENDARG_MODIFY_PARMS
,
236 TEXPIPE_ALPHA
| TEXBLEND_ARG2
| TEXBLENDARG_MODIFY_PARMS
,
237 TEXPIPE_ALPHA
| TEXBLEND_ARG0
| TEXBLENDARG_MODIFY_PARMS
,
239 static const GLuint op_rgb
[4] = {
242 TEXBLENDARG_REPLICATE_ALPHA
,
243 TEXBLENDARG_REPLICATE_ALPHA
| TEXBLENDARG_INV_ARG
,
248 imesa
->TexBlendWordsUsed
[unit
] = 0;
250 if(I830_DEBUG
&DEBUG_TEXTURE
)
251 fprintf(stderr
, "[%s:%u] env. mode = %s\n", __FUNCTION__
, __LINE__
,
252 _mesa_lookup_enum_by_nr(texUnit
->EnvMode
));
255 if ( !texUnit
->_ReallyEnabled
) {
256 imesa
->TexBlend
[unit
][0] = (STATE3D_MAP_BLEND_OP_CMD(unit
) |
258 ENABLE_TEXOUTPUT_WRT_SEL
|
259 TEXOP_OUTPUT_CURRENT
|
260 DISABLE_TEX_CNTRL_STAGE
|
264 imesa
->TexBlend
[unit
][1] = (STATE3D_MAP_BLEND_OP_CMD(unit
) |
266 ENABLE_TEXOUTPUT_WRT_SEL
|
267 TEXOP_OUTPUT_CURRENT
|
271 imesa
->TexBlend
[unit
][2] = (STATE3D_MAP_BLEND_ARG_CMD(unit
) |
274 TEXBLENDARG_MODIFY_PARMS
|
275 TEXBLENDARG_CURRENT
);
276 imesa
->TexBlend
[unit
][3] = (STATE3D_MAP_BLEND_ARG_CMD(unit
) |
279 TEXBLENDARG_MODIFY_PARMS
|
280 TEXBLENDARG_CURRENT
);
281 imesa
->TexBlendColorPipeNum
[unit
] = 0;
282 imesa
->TexBlendWordsUsed
[unit
] = 4;
285 switch(texUnit
->_CurrentCombine
->ModeRGB
) {
287 blendop
= TEXBLENDOP_ARG1
;
290 blendop
= TEXBLENDOP_MODULATE
;
293 blendop
= TEXBLENDOP_ADD
;
296 blendop
= TEXBLENDOP_ADDSIGNED
;
299 blendop
= TEXBLENDOP_BLEND
;
302 blendop
= TEXBLENDOP_SUBTRACT
;
304 case GL_DOT3_RGB_EXT
:
305 case GL_DOT3_RGBA_EXT
:
306 /* The EXT version of the DOT3 extension does not support the
307 * scale factor, but the ARB version (and the version in OpenGL
316 blendop
= TEXBLENDOP_DOT3
;
322 blendop
|= (rgb_shift
<< TEXOP_SCALE_SHIFT
);
324 switch(texUnit
->_CurrentCombine
->ModeA
) {
326 ablendop
= TEXBLENDOP_ARG1
;
329 ablendop
= TEXBLENDOP_MODULATE
;
332 ablendop
= TEXBLENDOP_ADD
;
335 ablendop
= TEXBLENDOP_ADDSIGNED
;
338 ablendop
= TEXBLENDOP_BLEND
;
341 ablendop
= TEXBLENDOP_SUBTRACT
;
347 if ( (texUnit
->_CurrentCombine
->ModeRGB
== GL_DOT3_RGBA_EXT
)
348 || (texUnit
->_CurrentCombine
->ModeRGB
== GL_DOT3_RGBA
) ) {
349 ablendop
= TEXBLENDOP_DOT3
;
352 ablendop
|= (alpha_shift
<< TEXOP_SCALE_SHIFT
);
354 /* Handle RGB args */
355 for( i
= 0 ; i
< numColorArgs
; i
++ ) {
356 const int op
= texUnit
->_CurrentCombine
->OperandRGB
[i
] - GL_SRC_COLOR
;
358 assert( (op
>= 0) && (op
<= 3) );
359 switch(texUnit
->_CurrentCombine
->SourceRGB
[i
]) {
361 args_RGB
[i
] = TEXBLENDARG_TEXEL0
+ unit
;
367 args_RGB
[i
] = TEXBLENDARG_TEXEL0
368 + (texUnit
->_CurrentCombine
->SourceRGB
[i
] & 0x03);
371 args_RGB
[i
] = TEXBLENDARG_FACTOR_N
;
372 need_constant_color
= GL_TRUE
;
374 case GL_PRIMARY_COLOR
:
375 args_RGB
[i
] = TEXBLENDARG_DIFFUSE
;
378 args_RGB
[i
] = TEXBLENDARG_CURRENT
;
381 args_RGB
[i
] = TEXBLENDARG_ONE
;
384 args_RGB
[i
] = TEXBLENDARG_ONE
| TEXBLENDARG_INV_ARG
;
390 /* Xor is used so that GL_ONE_MINUS_SRC_COLOR with GL_ZERO
393 args_RGB
[i
] ^= op_rgb
[op
];
397 for( i
= 0 ; i
< numAlphaArgs
; i
++ ) {
398 const int op
= texUnit
->_CurrentCombine
->OperandA
[i
] - GL_SRC_ALPHA
;
400 assert( (op
>= 0) && (op
<= 1) );
401 switch(texUnit
->_CurrentCombine
->SourceA
[i
]) {
403 args_A
[i
] = TEXBLENDARG_TEXEL0
+ unit
;
409 args_A
[i
] = TEXBLENDARG_TEXEL0
410 + (texUnit
->_CurrentCombine
->SourceA
[i
] & 0x03);
413 args_A
[i
] = TEXBLENDARG_FACTOR_N
;
414 need_constant_color
= GL_TRUE
;
416 case GL_PRIMARY_COLOR
:
417 args_A
[i
] = TEXBLENDARG_DIFFUSE
;
420 args_A
[i
] = TEXBLENDARG_CURRENT
;
423 args_A
[i
] = TEXBLENDARG_ONE
;
426 args_A
[i
] = TEXBLENDARG_ONE
| TEXBLENDARG_INV_ARG
;
432 /* We cheat. :) The register values for this are the same as for
433 * RGB. Xor is used so that GL_ONE_MINUS_SRC_ALPHA with GL_ZERO
436 args_A
[i
] ^= op_rgb
[op
];
439 /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */
440 /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */
441 /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */
443 /* When we render we need to figure out which is the last really enabled
444 * tex unit, and put last stage on it
447 imesa
->TexBlendColorPipeNum
[unit
] = 0;
450 /* Build color pipeline */
452 imesa
->TexBlend
[unit
][used
++] = (STATE3D_MAP_BLEND_OP_CMD(unit
) |
454 ENABLE_TEXOUTPUT_WRT_SEL
|
455 TEXOP_OUTPUT_CURRENT
|
456 DISABLE_TEX_CNTRL_STAGE
|
460 imesa
->TexBlend
[unit
][used
++] = (STATE3D_MAP_BLEND_OP_CMD(unit
) |
462 ENABLE_TEXOUTPUT_WRT_SEL
|
463 TEXOP_OUTPUT_CURRENT
|
467 for ( i
= 0 ; i
< numColorArgs
; i
++ ) {
468 imesa
->TexBlend
[unit
][used
++] = (STATE3D_MAP_BLEND_ARG_CMD(unit
) |
473 for ( i
= 0 ; i
< numAlphaArgs
; i
++ ) {
474 imesa
->TexBlend
[unit
][used
++] = (STATE3D_MAP_BLEND_ARG_CMD(unit
) |
480 if ( need_constant_color
) {
482 const GLfloat
* const fc
= texUnit
->EnvColor
;
484 FLOAT_COLOR_TO_UBYTE_COLOR(r
, fc
[RCOMP
]);
485 FLOAT_COLOR_TO_UBYTE_COLOR(g
, fc
[GCOMP
]);
486 FLOAT_COLOR_TO_UBYTE_COLOR(b
, fc
[BCOMP
]);
487 FLOAT_COLOR_TO_UBYTE_COLOR(a
, fc
[ACOMP
]);
489 imesa
->TexBlend
[unit
][used
++] = STATE3D_COLOR_FACTOR_CMD(unit
);
490 imesa
->TexBlend
[unit
][used
++] = ((a
<< 24) | (r
<< 16) | (g
<< 8) | b
);
493 imesa
->TexBlendWordsUsed
[unit
] = used
;
496 I830_STATECHANGE( imesa
, I830_UPLOAD_TEXBLEND_N(unit
) );
500 /* This is bogus -- can't load the same texture object on two units.
502 static void i830TexSetUnit( i830TextureObjectPtr t
, GLuint unit
)
504 if(I830_DEBUG
&DEBUG_TEXTURE
)
505 fprintf(stderr
, "%s unit(%d)\n", __FUNCTION__
, unit
);
507 t
->Setup
[I830_TEXREG_TM0LI
] = (STATE3D_LOAD_STATE_IMMEDIATE_2
|
508 (LOAD_TEXTURE_MAP0
<< unit
) | 4);
510 I830_SET_FIELD(t
->Setup
[I830_TEXREG_MCS
], MAP_UNIT_MASK
, MAP_UNIT(unit
));
512 t
->current_unit
= unit
;
513 t
->base
.bound
|= (1U << unit
);
516 #define TEXCOORDTYPE_MASK (~((1<<13)|(1<<12)|(1<<11)))
519 static GLboolean
enable_tex_common( GLcontext
*ctx
, GLuint unit
)
521 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
522 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
523 struct gl_texture_object
*tObj
= texUnit
->_Current
;
524 i830TextureObjectPtr t
= (i830TextureObjectPtr
)tObj
->DriverData
;
526 /* Fallback if there's a texture border */
527 if ( tObj
->Image
[0][tObj
->BaseLevel
]->Border
> 0 ) {
531 /* Upload teximages (not pipelined)
533 if (t
->base
.dirty_images
[0]) {
534 i830SetTexImages( imesa
, tObj
);
535 if (!t
->base
.memBlock
) {
540 /* Update state if this is a different texture object to last
543 if (imesa
->CurrentTexObj
[unit
] != t
) {
545 if ( imesa
->CurrentTexObj
[unit
] != NULL
) {
546 /* The old texture is no longer bound to this texture unit.
550 imesa
->CurrentTexObj
[unit
]->base
.bound
&= ~(1U << unit
);
553 I830_STATECHANGE( imesa
, I830_UPLOAD_TEX_N(unit
) );
554 imesa
->CurrentTexObj
[unit
] = t
;
555 i830TexSetUnit(t
, unit
);
558 /* Update texture environment if texture object image format or
559 * texture environment state has changed.
561 * KW: doesn't work -- change from tex0 only to tex0+tex1 gets
562 * missed (need to update last stage flag?). Call
563 * i830UpdateTexEnv always.
565 if (tObj
->Image
[0][tObj
->BaseLevel
]->Format
!=
566 imesa
->TexEnvImageFmt
[unit
]) {
567 imesa
->TexEnvImageFmt
[unit
] = tObj
->Image
[0][tObj
->BaseLevel
]->Format
;
569 i830UpdateTexEnv( ctx
, unit
);
570 imesa
->TexEnabledMask
|= I830_TEX_UNIT_ENABLED(unit
);
575 static GLboolean
enable_tex_rect( GLcontext
*ctx
, GLuint unit
)
577 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
578 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
579 struct gl_texture_object
*tObj
= texUnit
->_Current
;
580 i830TextureObjectPtr t
= (i830TextureObjectPtr
)tObj
->DriverData
;
581 GLuint mcs
= t
->Setup
[I830_TEXREG_MCS
];
583 mcs
&= ~TEXCOORDS_ARE_NORMAL
;
584 mcs
|= TEXCOORDS_ARE_IN_TEXELUNITS
;
586 if (mcs
!= t
->Setup
[I830_TEXREG_MCS
]) {
587 I830_STATECHANGE( imesa
, I830_UPLOAD_TEX_N(unit
) );
588 t
->Setup
[I830_TEXREG_MCS
] = mcs
;
595 static GLboolean
enable_tex_2d( GLcontext
*ctx
, GLuint unit
)
597 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
598 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
599 struct gl_texture_object
*tObj
= texUnit
->_Current
;
600 i830TextureObjectPtr t
= (i830TextureObjectPtr
)tObj
->DriverData
;
601 GLuint mcs
= t
->Setup
[I830_TEXREG_MCS
];
603 mcs
&= ~TEXCOORDS_ARE_IN_TEXELUNITS
;
604 mcs
|= TEXCOORDS_ARE_NORMAL
;
606 if (mcs
!= t
->Setup
[I830_TEXREG_MCS
]) {
607 I830_STATECHANGE( imesa
, I830_UPLOAD_TEX_N(unit
) );
608 t
->Setup
[I830_TEXREG_MCS
] = mcs
;
615 static GLboolean
disable_tex( GLcontext
*ctx
, int unit
)
617 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
619 /* This is happening too often. I need to conditionally send diffuse
620 * state to the card. Perhaps a diffuse dirty flag of some kind.
621 * Will need to change this logic if more than 2 texture units are
622 * used. We need to only do this up to the last unit enabled, or unit
623 * one if nothing is enabled.
626 if ( imesa
->CurrentTexObj
[unit
] != NULL
) {
627 /* The old texture is no longer bound to this texture unit.
631 imesa
->CurrentTexObj
[unit
]->base
.bound
&= ~(1U << unit
);
632 imesa
->CurrentTexObj
[unit
] = NULL
;
635 imesa
->TexEnvImageFmt
[unit
] = 0;
636 imesa
->dirty
&= ~(I830_UPLOAD_TEX_N(unit
));
638 i830UpdateTexEnv( ctx
, unit
);
643 static GLboolean
i830UpdateTexUnit( GLcontext
*ctx
, GLuint unit
)
645 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
646 struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[unit
];
648 imesa
->TexEnabledMask
&= ~(I830_TEX_UNIT_ENABLED(unit
));
650 if (texUnit
->_ReallyEnabled
== TEXTURE_2D_BIT
) {
651 return (enable_tex_common( ctx
, unit
) &&
652 enable_tex_2d( ctx
, unit
));
654 else if (texUnit
->_ReallyEnabled
== TEXTURE_RECT_BIT
) {
655 return (enable_tex_common( ctx
, unit
) &&
656 enable_tex_rect( ctx
, unit
));
658 else if (texUnit
->_ReallyEnabled
) {
662 disable_tex( ctx
, unit
);
669 /* Only deal with unit 0 and 1 for right now */
670 void i830UpdateTextureState( GLcontext
*ctx
)
672 i830ContextPtr imesa
= I830_CONTEXT(ctx
);
676 ok
= (i830UpdateTexUnit( ctx
, 0 ) &&
677 i830UpdateTexUnit( ctx
, 1 ) &&
678 i830UpdateTexUnit( ctx
, 2 ) &&
679 i830UpdateTexUnit( ctx
, 3 ));
681 FALLBACK( imesa
, I830_FALLBACK_TEXTURE
, !ok
);
684 /* Make sure last stage is set correctly */
685 if(imesa
->TexEnabledMask
& I830_TEX_UNIT_ENABLED(3)) {
686 pipe_num
= imesa
->TexBlendColorPipeNum
[3];
687 imesa
->TexBlend
[3][pipe_num
] |= TEXOP_LAST_STAGE
;
688 } else if(imesa
->TexEnabledMask
& I830_TEX_UNIT_ENABLED(2)) {
689 pipe_num
= imesa
->TexBlendColorPipeNum
[2];
690 imesa
->TexBlend
[2][pipe_num
] |= TEXOP_LAST_STAGE
;
691 } else if(imesa
->TexEnabledMask
& I830_TEX_UNIT_ENABLED(1)) {
692 pipe_num
= imesa
->TexBlendColorPipeNum
[1];
693 imesa
->TexBlend
[1][pipe_num
] |= TEXOP_LAST_STAGE
;
695 pipe_num
= imesa
->TexBlendColorPipeNum
[0];
696 imesa
->TexBlend
[0][pipe_num
] |= TEXOP_LAST_STAGE
;