(Stephane Marchesin, me) add hyperz support to radeon and r200 drivers. Only fast...
[mesa.git] / src / mesa / drivers / dri / i830 / i830_texstate.c
1 /**************************************************************************
2
3 Copyright 2001 2d3d Inc., Delray Beach, FL
4
5 All Rights Reserved.
6
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:
13
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
16 Software.
17
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.
25
26 **************************************************************************/
27
28 /* $XFree86: xc/lib/GL/mesa/src/drv/i830/i830_texstate.c,v 1.3 2002/12/10 01:26:53 dawes Exp $ */
29
30 /**
31 * \file i830_texstate.c
32 *
33 * Heavily based on the I810 driver, which was written by Keith Whitwell.
34 *
35 * \author Jeff Hartmann <jhartmann@2d3d.com>
36 * \author Keith Whitwell <keithw@tungstengraphics.com>
37 */
38
39 #include "glheader.h"
40 #include "macros.h"
41 #include "mtypes.h"
42 #include "simple_list.h"
43 #include "enums.h"
44 #include "texformat.h"
45 #include "texstore.h"
46
47 #include "mm.h"
48
49 #include "i830_screen.h"
50 #include "i830_dri.h"
51
52 #include "i830_context.h"
53 #include "i830_tex.h"
54 #include "i830_state.h"
55 #include "i830_ioctl.h"
56
57 #define I830_TEX_UNIT_ENABLED(unit) (1<<unit)
58
59 static void i830SetTexImages( i830ContextPtr imesa,
60 struct gl_texture_object *tObj )
61 {
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];
65 GLint numLevels;
66
67 switch( baseImage->TexFormat->MesaFormat ) {
68 case MESA_FORMAT_L8:
69 t->texelBytes = 1;
70 textureFormat = MAPSURF_8BIT | MT_8BIT_L8;
71 break;
72
73 case MESA_FORMAT_I8:
74 t->texelBytes = 1;
75 textureFormat = MAPSURF_8BIT | MT_8BIT_I8;
76 break;
77
78 case MESA_FORMAT_AL88:
79 t->texelBytes = 2;
80 textureFormat = MAPSURF_16BIT | MT_16BIT_AY88;
81 break;
82
83 case MESA_FORMAT_RGB565:
84 t->texelBytes = 2;
85 textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565;
86 break;
87
88 case MESA_FORMAT_ARGB1555:
89 t->texelBytes = 2;
90 textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555;
91 break;
92
93 case MESA_FORMAT_ARGB4444:
94 t->texelBytes = 2;
95 textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB4444;
96 break;
97
98 case MESA_FORMAT_ARGB8888:
99 t->texelBytes = 4;
100 textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888;
101 break;
102
103 case MESA_FORMAT_YCBCR_REV:
104 t->texelBytes = 2;
105 textureFormat = (MAPSURF_422 | MT_422_YCRCB_NORMAL |
106 TM0S1_COLORSPACE_CONVERSION);
107 break;
108
109 case MESA_FORMAT_YCBCR:
110 t->texelBytes = 2;
111 textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY | /* ??? */
112 TM0S1_COLORSPACE_CONVERSION);
113 break;
114
115 case MESA_FORMAT_RGB_FXT1:
116 case MESA_FORMAT_RGBA_FXT1:
117 t->texelBytes = 2;
118 textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1);
119 break;
120 case MESA_FORMAT_RGBA_DXT1:
121 case MESA_FORMAT_RGB_DXT1:
122 /*
123 * DXTn pitches are Width/4 * blocksize in bytes
124 * for DXT1: blocksize=8 so Width/4*8 = Width * 2
125 * for DXT3/5: blocksize=16 so Width/4*16 = Width * 4
126 */
127 t->texelBytes = 2;
128 textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1);
129 break;
130 case MESA_FORMAT_RGBA_DXT3:
131 t->texelBytes = 4;
132 textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3);
133 break;
134 case MESA_FORMAT_RGBA_DXT5:
135 t->texelBytes = 4;
136 textureFormat = (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5);
137 break;
138 default:
139 fprintf(stderr, "%s: bad image format\n", __FUNCTION__);
140 free( t );
141 return;
142 }
143
144 /* Compute which mipmap levels we really want to send to the hardware.
145 */
146
147 driCalculateTextureFirstLastLevel( (driTextureObject *) t );
148
149
150 /* Figure out the amount of memory required to hold all the mipmap
151 * levels. Choose the smallest pitch to accomodate the largest
152 * mipmap:
153 */
154 numLevels = t->base.lastLevel - t->base.firstLevel + 1;
155
156 /* Pitch would be subject to additional rules if texture memory were
157 * tiled. Currently it isn't.
158 */
159 if (0) {
160 pitch = 128;
161 while (pitch < tObj->Image[0][t->base.firstLevel]->Width * t->texelBytes)
162 pitch *= 2;
163 }
164 else {
165 pitch = tObj->Image[0][t->base.firstLevel]->Width * t->texelBytes;
166 pitch = (pitch + 3) & ~3;
167 }
168
169
170 /* All images must be loaded at this pitch. Count the number of
171 * lines required:
172 */
173 for ( total_height = i = 0 ; i < numLevels ; i++ ) {
174 t->image[0][i].image = tObj->Image[0][t->base.firstLevel + i];
175 if (!t->image[0][i].image)
176 break;
177
178 t->image[0][i].offset = total_height * pitch;
179 if (t->image[0][i].image->IsCompressed)
180 {
181 if (t->image[0][i].image->Height > 4)
182 total_height += t->image[0][i].image->Height/4;
183 else
184 total_height += 1;
185 }
186 else
187 total_height += t->image[0][i].image->Height;
188 t->image[0][i].internalFormat = baseImage->Format;
189 }
190
191 t->Pitch = pitch;
192 t->base.totalSize = total_height*pitch;
193 t->Setup[I830_TEXREG_TM0S1] =
194 (((tObj->Image[0][t->base.firstLevel]->Height - 1) << TM0S1_HEIGHT_SHIFT) |
195 ((tObj->Image[0][t->base.firstLevel]->Width - 1) << TM0S1_WIDTH_SHIFT) |
196 textureFormat);
197 t->Setup[I830_TEXREG_TM0S2] =
198 ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT));
199 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAX_MIP_MASK;
200 t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_MIP_MASK;
201 t->Setup[I830_TEXREG_TM0S3] |= ((numLevels - 1)*4) << TM0S3_MIN_MIP_SHIFT;
202 t->dirty = I830_UPLOAD_TEX0 | I830_UPLOAD_TEX1
203 | I830_UPLOAD_TEX2 | I830_UPLOAD_TEX3;
204
205 LOCK_HARDWARE( imesa );
206 i830UploadTexImagesLocked( imesa, t );
207 UNLOCK_HARDWARE( imesa );
208 }
209
210 /* ================================================================
211 * Texture combine functions
212 */
213
214
215 /**
216 * Calculate the hardware instuctions to setup the current texture enviromnemt
217 * settings. Since \c gl_texture_unit::_CurrentCombine is used, both
218 * "classic" texture enviroments and GL_ARB_texture_env_combine type texture
219 * environments are treated identically.
220 *
221 * \todo
222 * This function should return \c GLboolean. When \c GL_FALSE is returned,
223 * it means that an environment is selected that the hardware cannot do. This
224 * is the way the Radeon and R200 drivers work.
225 *
226 * \todo
227 * Looking at i830_3d_regs.h, it seems the i830 can do part of
228 * GL_ATI_texture_env_combine3. It can handle using \c GL_ONE and
229 * \c GL_ZERO as combine inputs (which the code already supports). It can
230 * also handle the \c GL_MODULATE_ADD_ATI mode. Is it worth investigating
231 * partial support for the extension?
232 *
233 * \todo
234 * Some thought needs to be put into the way combiners work. The driver
235 * treats the hardware as if there's a specific combine unit tied to each
236 * texture unit. That's why there's the special case for a disabled texture
237 * unit. That's not the way the hardware works. In reality, there are 4
238 * texture units and four general instruction slots. Each instruction slot
239 * can use any texture as an input. There's no need for this wierd "no-op"
240 * stuff. If texture units 0 and 3 are enabled, the instructions to combine
241 * them should be in slots 0 and 1, not 0 and 3 with two no-ops inbetween.
242 */
243
244 static void i830UpdateTexEnv( GLcontext *ctx, GLuint unit )
245 {
246 i830ContextPtr imesa = I830_CONTEXT(ctx);
247 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
248 const GLuint numColorArgs = texUnit->_CurrentCombine->_NumArgsRGB;
249 const GLuint numAlphaArgs = texUnit->_CurrentCombine->_NumArgsA;
250
251 GLboolean need_constant_color = GL_FALSE;
252 GLuint blendop;
253 GLuint ablendop;
254 GLuint args_RGB[3];
255 GLuint args_A[3];
256 GLuint rgb_shift = texUnit->Combine.ScaleShiftRGB;
257 GLuint alpha_shift = texUnit->Combine.ScaleShiftA;
258 int i;
259 unsigned used;
260 static const GLuint tex_blend_rgb[3] = {
261 TEXPIPE_COLOR | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS,
262 TEXPIPE_COLOR | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS,
263 TEXPIPE_COLOR | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS,
264 };
265 static const GLuint tex_blend_a[3] = {
266 TEXPIPE_ALPHA | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS,
267 TEXPIPE_ALPHA | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS,
268 TEXPIPE_ALPHA | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS,
269 };
270 static const GLuint op_rgb[4] = {
271 0,
272 TEXBLENDARG_INV_ARG,
273 TEXBLENDARG_REPLICATE_ALPHA,
274 TEXBLENDARG_REPLICATE_ALPHA | TEXBLENDARG_INV_ARG,
275 };
276
277
278
279 imesa->TexBlendWordsUsed[unit] = 0;
280
281 if(I830_DEBUG&DEBUG_TEXTURE)
282 fprintf(stderr, "[%s:%u] env. mode = %s\n", __FUNCTION__, __LINE__,
283 _mesa_lookup_enum_by_nr(texUnit->EnvMode));
284
285
286 if ( !texUnit->_ReallyEnabled ) {
287 imesa->TexBlend[unit][0] = (STATE3D_MAP_BLEND_OP_CMD(unit) |
288 TEXPIPE_COLOR |
289 ENABLE_TEXOUTPUT_WRT_SEL |
290 TEXOP_OUTPUT_CURRENT |
291 DISABLE_TEX_CNTRL_STAGE |
292 TEXOP_SCALE_1X |
293 TEXOP_MODIFY_PARMS |
294 TEXBLENDOP_ARG1);
295 imesa->TexBlend[unit][1] = (STATE3D_MAP_BLEND_OP_CMD(unit) |
296 TEXPIPE_ALPHA |
297 ENABLE_TEXOUTPUT_WRT_SEL |
298 TEXOP_OUTPUT_CURRENT |
299 TEXOP_SCALE_1X |
300 TEXOP_MODIFY_PARMS |
301 TEXBLENDOP_ARG1);
302 imesa->TexBlend[unit][2] = (STATE3D_MAP_BLEND_ARG_CMD(unit) |
303 TEXPIPE_COLOR |
304 TEXBLEND_ARG1 |
305 TEXBLENDARG_MODIFY_PARMS |
306 TEXBLENDARG_CURRENT);
307 imesa->TexBlend[unit][3] = (STATE3D_MAP_BLEND_ARG_CMD(unit) |
308 TEXPIPE_ALPHA |
309 TEXBLEND_ARG1 |
310 TEXBLENDARG_MODIFY_PARMS |
311 TEXBLENDARG_CURRENT);
312 imesa->TexBlendWordsUsed[unit] = 4;
313 }
314 else {
315 switch(texUnit->_CurrentCombine->ModeRGB) {
316 case GL_REPLACE:
317 blendop = TEXBLENDOP_ARG1;
318 break;
319 case GL_MODULATE:
320 blendop = TEXBLENDOP_MODULATE;
321 break;
322 case GL_ADD:
323 blendop = TEXBLENDOP_ADD;
324 break;
325 case GL_ADD_SIGNED:
326 blendop = TEXBLENDOP_ADDSIGNED;
327 break;
328 case GL_INTERPOLATE:
329 blendop = TEXBLENDOP_BLEND;
330 break;
331 case GL_SUBTRACT:
332 blendop = TEXBLENDOP_SUBTRACT;
333 break;
334 case GL_DOT3_RGB_EXT:
335 case GL_DOT3_RGBA_EXT:
336 /* The EXT version of the DOT3 extension does not support the
337 * scale factor, but the ARB version (and the version in OpenGL
338 * 1.3) does.
339 */
340 rgb_shift = 0;
341 alpha_shift = 0;
342 /* FALLTHROUGH */
343
344 case GL_DOT3_RGB:
345 case GL_DOT3_RGBA:
346 blendop = TEXBLENDOP_DOT3;
347 break;
348 default:
349 return;
350 }
351
352 blendop |= (rgb_shift << TEXOP_SCALE_SHIFT);
353
354 switch(texUnit->_CurrentCombine->ModeA) {
355 case GL_REPLACE:
356 ablendop = TEXBLENDOP_ARG1;
357 break;
358 case GL_MODULATE:
359 ablendop = TEXBLENDOP_MODULATE;
360 break;
361 case GL_ADD:
362 ablendop = TEXBLENDOP_ADD;
363 break;
364 case GL_ADD_SIGNED:
365 ablendop = TEXBLENDOP_ADDSIGNED;
366 break;
367 case GL_INTERPOLATE:
368 ablendop = TEXBLENDOP_BLEND;
369 break;
370 case GL_SUBTRACT:
371 ablendop = TEXBLENDOP_SUBTRACT;
372 break;
373 default:
374 return;
375 }
376
377 if ( (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA_EXT)
378 || (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA) ) {
379 ablendop = TEXBLENDOP_DOT3;
380 }
381
382 ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT);
383
384 /* Handle RGB args */
385 for( i = 0 ; i < numColorArgs ; i++ ) {
386 const int op = texUnit->_CurrentCombine->OperandRGB[i] - GL_SRC_COLOR;
387
388 assert( (op >= 0) && (op <= 3) );
389 switch(texUnit->_CurrentCombine->SourceRGB[i]) {
390 case GL_TEXTURE:
391 args_RGB[i] = TEXBLENDARG_TEXEL0 + unit;
392 break;
393 case GL_TEXTURE0:
394 case GL_TEXTURE1:
395 case GL_TEXTURE2:
396 case GL_TEXTURE3:
397 args_RGB[i] = TEXBLENDARG_TEXEL0
398 + (texUnit->_CurrentCombine->SourceRGB[i] & 0x03);
399 break;
400 case GL_CONSTANT:
401 args_RGB[i] = TEXBLENDARG_FACTOR_N;
402 need_constant_color = GL_TRUE;
403 break;
404 case GL_PRIMARY_COLOR:
405 args_RGB[i] = TEXBLENDARG_DIFFUSE;
406 break;
407 case GL_PREVIOUS:
408 args_RGB[i] = TEXBLENDARG_CURRENT;
409 break;
410 case GL_ONE:
411 args_RGB[i] = TEXBLENDARG_ONE;
412 break;
413 case GL_ZERO:
414 args_RGB[i] = TEXBLENDARG_ONE | TEXBLENDARG_INV_ARG;
415 break;
416 default:
417 return;
418 }
419
420 /* Xor is used so that GL_ONE_MINUS_SRC_COLOR with GL_ZERO
421 * works correctly.
422 */
423 args_RGB[i] ^= op_rgb[op];
424 }
425
426 /* Handle A args */
427 for( i = 0 ; i < numAlphaArgs ; i++ ) {
428 const int op = texUnit->_CurrentCombine->OperandA[i] - GL_SRC_ALPHA;
429
430 assert( (op >= 0) && (op <= 1) );
431 switch(texUnit->_CurrentCombine->SourceA[i]) {
432 case GL_TEXTURE:
433 args_A[i] = TEXBLENDARG_TEXEL0 + unit;
434 break;
435 case GL_TEXTURE0:
436 case GL_TEXTURE1:
437 case GL_TEXTURE2:
438 case GL_TEXTURE3:
439 args_A[i] = TEXBLENDARG_TEXEL0
440 + (texUnit->_CurrentCombine->SourceA[i] & 0x03);
441 break;
442 case GL_CONSTANT:
443 args_A[i] = TEXBLENDARG_FACTOR_N;
444 need_constant_color = GL_TRUE;
445 break;
446 case GL_PRIMARY_COLOR:
447 args_A[i] = TEXBLENDARG_DIFFUSE;
448 break;
449 case GL_PREVIOUS:
450 args_A[i] = TEXBLENDARG_CURRENT;
451 break;
452 case GL_ONE:
453 args_A[i] = TEXBLENDARG_ONE;
454 break;
455 case GL_ZERO:
456 args_A[i] = TEXBLENDARG_ONE | TEXBLENDARG_INV_ARG;
457 break;
458 default:
459 return;
460 }
461
462 /* We cheat. :) The register values for this are the same as for
463 * RGB. Xor is used so that GL_ONE_MINUS_SRC_ALPHA with GL_ZERO
464 * works correctly.
465 */
466 args_A[i] ^= op_rgb[op];
467 }
468
469 /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */
470 /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */
471 /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */
472
473 /* Build color pipeline */
474
475 used = 0;
476 imesa->TexBlend[unit][used++] = (STATE3D_MAP_BLEND_OP_CMD(unit) |
477 TEXPIPE_COLOR |
478 ENABLE_TEXOUTPUT_WRT_SEL |
479 TEXOP_OUTPUT_CURRENT |
480 DISABLE_TEX_CNTRL_STAGE |
481 TEXOP_MODIFY_PARMS |
482 blendop);
483
484 imesa->TexBlend[unit][used++] = (STATE3D_MAP_BLEND_OP_CMD(unit) |
485 TEXPIPE_ALPHA |
486 ENABLE_TEXOUTPUT_WRT_SEL |
487 TEXOP_OUTPUT_CURRENT |
488 TEXOP_MODIFY_PARMS |
489 ablendop);
490
491 for ( i = 0 ; i < numColorArgs ; i++ ) {
492 imesa->TexBlend[unit][used++] = (STATE3D_MAP_BLEND_ARG_CMD(unit) |
493 tex_blend_rgb[i] |
494 args_RGB[i]);
495 }
496
497 for ( i = 0 ; i < numAlphaArgs ; i++ ) {
498 imesa->TexBlend[unit][used++] = (STATE3D_MAP_BLEND_ARG_CMD(unit) |
499 tex_blend_a[i] |
500 args_A[i]);
501 }
502
503
504 if ( need_constant_color ) {
505 GLubyte r, g, b, a;
506 const GLfloat * const fc = texUnit->EnvColor;
507
508 FLOAT_COLOR_TO_UBYTE_COLOR(r, fc[RCOMP]);
509 FLOAT_COLOR_TO_UBYTE_COLOR(g, fc[GCOMP]);
510 FLOAT_COLOR_TO_UBYTE_COLOR(b, fc[BCOMP]);
511 FLOAT_COLOR_TO_UBYTE_COLOR(a, fc[ACOMP]);
512
513 imesa->TexBlend[unit][used++] = STATE3D_COLOR_FACTOR_CMD(unit);
514 imesa->TexBlend[unit][used++] = ((a << 24) | (r << 16) | (g << 8) | b);
515 }
516
517 imesa->TexBlendWordsUsed[unit] = used;
518 }
519
520 I830_STATECHANGE( imesa, I830_UPLOAD_TEXBLEND_N(unit) );
521 }
522
523
524 /* This is bogus -- can't load the same texture object on two units.
525 */
526 static void i830TexSetUnit( i830TextureObjectPtr t, GLuint unit )
527 {
528 if(I830_DEBUG&DEBUG_TEXTURE)
529 fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit);
530
531 t->Setup[I830_TEXREG_TM0LI] = (STATE3D_LOAD_STATE_IMMEDIATE_2 |
532 (LOAD_TEXTURE_MAP0 << unit) | 4);
533
534 I830_SET_FIELD(t->Setup[I830_TEXREG_MCS], MAP_UNIT_MASK, MAP_UNIT(unit));
535
536 t->current_unit = unit;
537 t->base.bound |= (1U << unit);
538 }
539
540 #define TEXCOORDTYPE_MASK (~((1<<13)|(1<<12)|(1<<11)))
541
542
543 static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit )
544 {
545 i830ContextPtr imesa = I830_CONTEXT(ctx);
546 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
547 struct gl_texture_object *tObj = texUnit->_Current;
548 i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData;
549
550 /* Fallback if there's a texture border */
551 if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) {
552 return GL_FALSE;
553 }
554
555 /* Upload teximages (not pipelined)
556 */
557 if (t->base.dirty_images[0]) {
558 i830SetTexImages( imesa, tObj );
559 if (!t->base.memBlock) {
560 return GL_FALSE;
561 }
562 }
563
564 /* Update state if this is a different texture object to last
565 * time.
566 */
567 if (imesa->CurrentTexObj[unit] != t) {
568
569 if ( imesa->CurrentTexObj[unit] != NULL ) {
570 /* The old texture is no longer bound to this texture unit.
571 * Mark it as such.
572 */
573
574 imesa->CurrentTexObj[unit]->base.bound &= ~(1U << unit);
575 }
576
577 I830_STATECHANGE( imesa, I830_UPLOAD_TEX_N(unit) );
578 imesa->CurrentTexObj[unit] = t;
579 i830TexSetUnit(t, unit);
580 }
581
582 /* Update texture environment if texture object image format or
583 * texture environment state has changed.
584 *
585 * KW: doesn't work -- change from tex0 only to tex0+tex1 gets
586 * missed (need to update last stage flag?). Call
587 * i830UpdateTexEnv always.
588 */
589 if (tObj->Image[0][tObj->BaseLevel]->Format !=
590 imesa->TexEnvImageFmt[unit]) {
591 imesa->TexEnvImageFmt[unit] = tObj->Image[0][tObj->BaseLevel]->Format;
592 }
593 i830UpdateTexEnv( ctx, unit );
594 imesa->TexEnabledMask |= I830_TEX_UNIT_ENABLED(unit);
595
596 return GL_TRUE;
597 }
598
599 static GLboolean enable_tex_rect( GLcontext *ctx, GLuint unit )
600 {
601 i830ContextPtr imesa = I830_CONTEXT(ctx);
602 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
603 struct gl_texture_object *tObj = texUnit->_Current;
604 i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData;
605 GLuint mcs = t->Setup[I830_TEXREG_MCS];
606
607 mcs &= ~TEXCOORDS_ARE_NORMAL;
608 mcs |= TEXCOORDS_ARE_IN_TEXELUNITS;
609
610 if (mcs != t->Setup[I830_TEXREG_MCS]) {
611 I830_STATECHANGE( imesa, I830_UPLOAD_TEX_N(unit) );
612 t->Setup[I830_TEXREG_MCS] = mcs;
613 }
614
615 return GL_TRUE;
616 }
617
618
619 static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit )
620 {
621 i830ContextPtr imesa = I830_CONTEXT(ctx);
622 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
623 struct gl_texture_object *tObj = texUnit->_Current;
624 i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData;
625 GLuint mcs = t->Setup[I830_TEXREG_MCS];
626
627 mcs &= ~TEXCOORDS_ARE_IN_TEXELUNITS;
628 mcs |= TEXCOORDS_ARE_NORMAL;
629
630 if (mcs != t->Setup[I830_TEXREG_MCS]) {
631 I830_STATECHANGE( imesa, I830_UPLOAD_TEX_N(unit) );
632 t->Setup[I830_TEXREG_MCS] = mcs;
633 }
634
635 return GL_TRUE;
636 }
637
638
639 static GLboolean disable_tex( GLcontext *ctx, int unit )
640 {
641 i830ContextPtr imesa = I830_CONTEXT(ctx);
642
643 /* This is happening too often. I need to conditionally send diffuse
644 * state to the card. Perhaps a diffuse dirty flag of some kind.
645 * Will need to change this logic if more than 2 texture units are
646 * used. We need to only do this up to the last unit enabled, or unit
647 * one if nothing is enabled.
648 */
649
650 if ( imesa->CurrentTexObj[unit] != NULL ) {
651 /* The old texture is no longer bound to this texture unit.
652 * Mark it as such.
653 */
654
655 imesa->CurrentTexObj[unit]->base.bound &= ~(1U << unit);
656 imesa->CurrentTexObj[unit] = NULL;
657 }
658
659 imesa->TexEnvImageFmt[unit] = 0;
660 imesa->dirty &= ~(I830_UPLOAD_TEX_N(unit));
661
662 i830UpdateTexEnv( ctx, unit );
663
664 return GL_TRUE;
665 }
666
667 static GLboolean i830UpdateTexUnit( GLcontext *ctx, GLuint unit )
668 {
669 i830ContextPtr imesa = I830_CONTEXT(ctx);
670 struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
671
672 imesa->TexEnabledMask &= ~(I830_TEX_UNIT_ENABLED(unit));
673
674 if (texUnit->_ReallyEnabled == TEXTURE_2D_BIT) {
675 return (enable_tex_common( ctx, unit ) &&
676 enable_tex_2d( ctx, unit ));
677 }
678 else if (texUnit->_ReallyEnabled == TEXTURE_RECT_BIT) {
679 return (enable_tex_common( ctx, unit ) &&
680 enable_tex_rect( ctx, unit ));
681 }
682 else if (texUnit->_ReallyEnabled) {
683 return GL_FALSE;
684 }
685 else {
686 return disable_tex( ctx, unit );
687 }
688 }
689
690
691
692 void i830UpdateTextureState( GLcontext *ctx )
693 {
694 i830ContextPtr imesa = I830_CONTEXT(ctx);
695 int i;
696 int last_stage = 0;
697 GLboolean ok;
698
699 for ( i = 0 ; i < ctx->Const.MaxTextureUnits ; i++ ) {
700 if ( (ctx->Texture.Unit[i]._ReallyEnabled == TEXTURE_2D_BIT)
701 || (ctx->Texture.Unit[i]._ReallyEnabled == TEXTURE_RECT_BIT) ) {
702 last_stage = i;
703 }
704 }
705
706 ok = GL_TRUE;
707 for ( i = 0 ; i <= last_stage ; i++ ) {
708 ok = ok && i830UpdateTexUnit( ctx, i );
709 }
710
711 FALLBACK( imesa, I830_FALLBACK_TEXTURE, !ok );
712
713
714 /* Make sure last stage is set correctly */
715 imesa->TexBlend[last_stage][0] |= TEXOP_LAST_STAGE;
716 }