1 /* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.7 2001/01/08 01:07:21 martin Exp $ */
2 /**************************************************************************
4 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 ATI, PRECISION INSIGHT AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Gareth Hughes <gareth@valinux.com>
32 * Kevin E. Martin <martin@valinux.com>
33 * Brian Paul <brianp@valinux.com>
40 #include "texformat.h"
42 #include "r128_context.h"
43 #include "r128_state.h"
44 #include "r128_ioctl.h"
46 #include "r128_tris.h"
50 static void r128SetTexImages( r128ContextPtr rmesa
,
51 const struct gl_texture_object
*tObj
)
53 r128TexObjPtr t
= (r128TexObjPtr
) tObj
->DriverData
;
54 struct gl_texture_image
*baseImage
= tObj
->Image
[tObj
->BaseLevel
];
55 int log2Pitch
, log2Height
, log2Size
, log2MinSize
;
58 GLint firstLevel
, lastLevel
;
63 if ( R128_DEBUG
& DEBUG_VERBOSE_API
)
64 fprintf( stderr
, "%s( %p )\n", __FUNCTION__
, tObj
);
66 switch (baseImage
->TexFormat
->MesaFormat
) {
67 case MESA_FORMAT_ARGB8888
:
68 t
->textureFormat
= R128_DATATYPE_ARGB8888
;
70 case MESA_FORMAT_ARGB4444
:
71 t
->textureFormat
= R128_DATATYPE_ARGB4444
;
73 case MESA_FORMAT_RGB565
:
74 t
->textureFormat
= R128_DATATYPE_RGB565
;
76 case MESA_FORMAT_RGB332
:
77 t
->textureFormat
= R128_DATATYPE_RGB8
;
80 t
->textureFormat
= R128_DATATYPE_CI8
;
82 case MESA_FORMAT_YCBCR
:
83 t
->textureFormat
= R128_DATATYPE_YVYU422
;
85 case MESA_FORMAT_YCBCR_REV
:
86 t
->textureFormat
= R128_DATATYPE_VYUY422
;
89 _mesa_problem(rmesa
->glCtx
, "Bad texture format in %s", __FUNCTION__
);
92 /* Compute which mipmap levels we really want to send to the hardware.
93 * This depends on the base image size, GL_TEXTURE_MIN_LOD,
94 * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
95 * Yes, this looks overly complicated, but it's all needed.
97 firstLevel
= tObj
->BaseLevel
+ (GLint
) (tObj
->MinLod
+ 0.5);
98 firstLevel
= MAX2(firstLevel
, tObj
->BaseLevel
);
99 lastLevel
= tObj
->BaseLevel
+ (GLint
) (tObj
->MaxLod
+ 0.5);
100 lastLevel
= MAX2(lastLevel
, tObj
->BaseLevel
);
101 lastLevel
= MIN2(lastLevel
, tObj
->BaseLevel
+ baseImage
->MaxLog2
);
102 lastLevel
= MIN2(lastLevel
, tObj
->MaxLevel
);
103 lastLevel
= MAX2(firstLevel
, lastLevel
); /* need at least one level */
105 log2Pitch
= tObj
->Image
[firstLevel
]->WidthLog2
;
106 log2Height
= tObj
->Image
[firstLevel
]->HeightLog2
;
107 log2Size
= MAX2(log2Pitch
, log2Height
);
108 log2MinSize
= log2Size
;
110 t
->base
.dirty_images
[0] = 0;
112 for ( i
= firstLevel
; i
<= lastLevel
; i
++ ) {
113 const struct gl_texture_image
*texImage
;
115 texImage
= tObj
->Image
[i
];
116 if ( !texImage
|| !texImage
->Data
) {
121 log2MinSize
= texImage
->MaxLog2
;
123 t
->image
[i
- firstLevel
].offset
= totalSize
;
124 t
->image
[i
- firstLevel
].width
= tObj
->Image
[i
]->Width
;
125 t
->image
[i
- firstLevel
].height
= tObj
->Image
[i
]->Height
;
127 t
->base
.dirty_images
[0] |= (1 << i
);
129 totalSize
+= (tObj
->Image
[i
]->Height
*
130 tObj
->Image
[i
]->Width
*
131 tObj
->Image
[i
]->TexFormat
->TexelBytes
);
133 /* Offsets must be 32-byte aligned for host data blits and tiling */
134 totalSize
= (totalSize
+ 31) & ~31;
137 t
->base
.totalSize
= totalSize
;
138 t
->base
.firstLevel
= firstLevel
;
139 t
->base
.lastLevel
= lastLevel
;
141 /* Set the texture format */
142 t
->setup
.tex_cntl
&= ~(0xf << 16);
143 t
->setup
.tex_cntl
|= t
->textureFormat
;
145 t
->setup
.tex_combine_cntl
= 0x00000000; /* XXX is this right? */
147 t
->setup
.tex_size_pitch
= ((log2Pitch
<< R128_TEX_PITCH_SHIFT
) |
148 (log2Size
<< R128_TEX_SIZE_SHIFT
) |
149 (log2Height
<< R128_TEX_HEIGHT_SHIFT
) |
150 (log2MinSize
<< R128_TEX_MIN_SIZE_SHIFT
));
152 for ( i
= 0 ; i
< R128_MAX_TEXTURE_LEVELS
; i
++ ) {
153 t
->setup
.tex_offset
[i
] = 0x00000000;
156 if (firstLevel
== lastLevel
)
157 t
->setup
.tex_cntl
|= R128_MIP_MAP_DISABLE
;
159 t
->setup
.tex_cntl
&= ~R128_MIP_MAP_DISABLE
;
161 /* FYI: r128UploadTexImages( rmesa, t ); used to be called here */
165 /* ================================================================
166 * Texture combine functions
169 #define COLOR_COMB_DISABLE (R128_COMB_DIS | \
170 R128_COLOR_FACTOR_TEX)
171 #define COLOR_COMB_COPY_INPUT (R128_COMB_COPY_INP | \
172 R128_COLOR_FACTOR_TEX)
173 #define COLOR_COMB_MODULATE (R128_COMB_MODULATE | \
174 R128_COLOR_FACTOR_TEX)
175 #define COLOR_COMB_MODULATE_NTEX (R128_COMB_MODULATE | \
176 R128_COLOR_FACTOR_NTEX)
177 #define COLOR_COMB_ADD (R128_COMB_ADD | \
178 R128_COLOR_FACTOR_TEX)
179 #define COLOR_COMB_BLEND_TEX (R128_COMB_BLEND_TEXTURE | \
180 R128_COLOR_FACTOR_TEX)
181 /* Rage 128 Pro/M3 only! */
182 #define COLOR_COMB_BLEND_COLOR (R128_COMB_MODULATE2X | \
183 R128_COMB_FCN_MSB | \
184 R128_COLOR_FACTOR_CONST_COLOR)
186 #define ALPHA_COMB_DISABLE (R128_COMB_ALPHA_DIS | \
187 R128_ALPHA_FACTOR_TEX_ALPHA)
188 #define ALPHA_COMB_COPY_INPUT (R128_COMB_ALPHA_COPY_INP | \
189 R128_ALPHA_FACTOR_TEX_ALPHA)
190 #define ALPHA_COMB_MODULATE (R128_COMB_ALPHA_MODULATE | \
191 R128_ALPHA_FACTOR_TEX_ALPHA)
192 #define ALPHA_COMB_MODULATE_NTEX (R128_COMB_ALPHA_MODULATE | \
193 R128_ALPHA_FACTOR_NTEX_ALPHA)
194 #define ALPHA_COMB_ADD (R128_COMB_ALPHA_ADD | \
195 R128_ALPHA_FACTOR_TEX_ALPHA)
197 #define INPUT_INTERP (R128_INPUT_FACTOR_INT_COLOR | \
198 R128_INP_FACTOR_A_INT_ALPHA)
199 #define INPUT_PREVIOUS (R128_INPUT_FACTOR_PREV_COLOR | \
200 R128_INP_FACTOR_A_PREV_ALPHA)
202 static GLboolean
r128UpdateTextureEnv( GLcontext
*ctx
, int unit
)
204 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
205 GLint source
= rmesa
->tmu_source
[unit
];
206 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
207 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
208 const GLenum format
= tObj
->Image
[tObj
->BaseLevel
]->Format
;
211 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
212 fprintf( stderr
, "%s( %p, %d )\n",
213 __FUNCTION__
, ctx
, unit
);
217 combine
= INPUT_INTERP
;
219 combine
= INPUT_PREVIOUS
;
222 /* Set the texture environment state */
223 switch ( texUnit
->EnvMode
) {
227 case GL_LUMINANCE_ALPHA
:
229 combine
|= (COLOR_COMB_DISABLE
| /* C = Ct */
230 ALPHA_COMB_DISABLE
); /* A = At */
234 combine
|= (COLOR_COMB_DISABLE
| /* C = Ct */
235 ALPHA_COMB_COPY_INPUT
); /* A = Af */
238 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
239 ALPHA_COMB_DISABLE
); /* A = At */
250 case GL_LUMINANCE_ALPHA
:
252 combine
|= (COLOR_COMB_MODULATE
| /* C = CfCt */
253 ALPHA_COMB_MODULATE
); /* A = AfAt */
257 combine
|= (COLOR_COMB_MODULATE
| /* C = CfCt */
258 ALPHA_COMB_COPY_INPUT
); /* A = Af */
261 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
262 ALPHA_COMB_MODULATE
); /* A = AfAt */
273 combine
|= (COLOR_COMB_BLEND_TEX
| /* C = Cf(1-At)+CtAt */
274 ALPHA_COMB_COPY_INPUT
); /* A = Af */
277 combine
|= (COLOR_COMB_DISABLE
| /* C = Ct */
278 ALPHA_COMB_COPY_INPUT
); /* A = Af */
282 case GL_LUMINANCE_ALPHA
:
284 /* Undefined behaviour - just copy the incoming fragment */
285 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = undefined */
286 ALPHA_COMB_COPY_INPUT
); /* A = undefined */
295 /* Rage 128 Pro and M3 can handle GL_BLEND texturing.
297 if ( !R128_IS_PLAIN( rmesa
) ) {
298 /* XXX this hasn't been fully tested, I don't have a Pro card. -BP */
301 case GL_LUMINANCE_ALPHA
:
302 combine
|= (COLOR_COMB_BLEND_COLOR
| /* C = Cf(1-Ct)+CcCt */
303 ALPHA_COMB_MODULATE
); /* A = AfAt */
308 combine
|= (COLOR_COMB_BLEND_COLOR
| /* C = Cf(1-Ct)+CcCt */
309 ALPHA_COMB_COPY_INPUT
); /* A = Af */
313 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
314 ALPHA_COMB_MODULATE
); /* A = AfAt */
318 /* GH: We could be smarter about this... */
319 switch ( rmesa
->env_color
& 0xff000000 ) {
321 combine
|= (COLOR_COMB_BLEND_COLOR
| /* C = Cf(1-It)+CcIt */
322 ALPHA_COMB_MODULATE_NTEX
); /* A = Af(1-It) */
324 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
325 ALPHA_COMB_MODULATE
); /* A = fallback */
337 /* Rage 128 has to fake some cases of GL_BLEND, otherwise fallback
338 * to software rendering.
340 if ( rmesa
->blend_flags
) {
345 case GL_LUMINANCE_ALPHA
:
346 switch ( rmesa
->env_color
& 0x00ffffff ) {
348 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
349 ALPHA_COMB_MODULATE
); /* A = AfAt */
352 /* This isn't right - BP */
355 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
356 ALPHA_COMB_MODULATE
); /* A = AfAt */
358 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
359 ALPHA_COMB_COPY_INPUT
); /* A = Af */
364 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
365 ALPHA_COMB_MODULATE
); /* A = fallback */
371 switch ( rmesa
->env_color
& 0x00ffffff ) {
373 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
374 ALPHA_COMB_COPY_INPUT
); /* A = Af */
377 /* This isn't right - BP */
380 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
381 ALPHA_COMB_COPY_INPUT
); /* A = Af */
383 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
384 ALPHA_COMB_COPY_INPUT
); /* A = Af */
389 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
390 ALPHA_COMB_COPY_INPUT
); /* A = fallback */
396 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
397 ALPHA_COMB_MODULATE
); /* A = AfAt */
399 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
400 ALPHA_COMB_COPY_INPUT
); /* A = Af */
404 switch ( rmesa
->env_color
& 0x00ffffff ) {
406 combine
|= COLOR_COMB_MODULATE_NTEX
; /* C = Cf(1-It) */
409 /* This isn't right - BP */
412 combine
|= COLOR_COMB_MODULATE_NTEX
; /* C = Cf(1-It) */
414 combine
|= COLOR_COMB_ADD
; /* C = Cf+It */
419 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
420 ALPHA_COMB_MODULATE
); /* A = fallback */
423 switch ( rmesa
->env_color
& 0xff000000 ) {
425 combine
|= ALPHA_COMB_MODULATE_NTEX
; /* A = Af(1-It) */
428 /* This isn't right - BP */
431 combine
|= ALPHA_COMB_MODULATE_NTEX
; /* A = Af(1-It) */
433 combine
|= ALPHA_COMB_ADD
; /* A = Af+It */
438 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
439 ALPHA_COMB_MODULATE
); /* A = fallback */
452 case GL_LUMINANCE_ALPHA
:
453 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
454 ALPHA_COMB_MODULATE
); /* A = AfAt */
458 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
459 ALPHA_COMB_COPY_INPUT
); /* A = Af */
462 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
463 ALPHA_COMB_MODULATE
); /* A = AfAt */
466 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
467 ALPHA_COMB_ADD
); /* A = Af+At */
479 if ( rmesa
->tex_combine
[unit
] != combine
) {
480 rmesa
->tex_combine
[unit
] = combine
;
481 rmesa
->dirty
|= R128_UPLOAD_TEX0
<< unit
;
486 static void disable_tex( GLcontext
*ctx
, int unit
)
488 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
490 FLUSH_BATCH( rmesa
);
492 if ( rmesa
->CurrentTexObj
[unit
] ) {
493 rmesa
->CurrentTexObj
[unit
]->base
.bound
&= ~(1 << unit
);
494 rmesa
->CurrentTexObj
[unit
] = NULL
;
497 rmesa
->setup
.tex_cntl_c
&= ~(R128_TEXMAP_ENABLE
<< unit
);
498 rmesa
->setup
.tex_size_pitch_c
&= ~(R128_TEX_SIZE_PITCH_MASK
<<
499 (R128_SEC_TEX_SIZE_PITCH_SHIFT
* unit
));
500 rmesa
->dirty
|= R128_UPLOAD_CONTEXT
;
502 /* If either texture unit is disabled, then multitexturing is not
506 rmesa
->blend_flags
&= ~R128_BLEND_MULTITEX
;
509 static GLboolean
enable_tex_2d( GLcontext
*ctx
, int unit
)
511 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
512 const int source
= rmesa
->tmu_source
[unit
];
513 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
514 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
515 r128TexObjPtr t
= (r128TexObjPtr
) tObj
->DriverData
;
517 /* Need to load the 2d images associated with this unit.
519 if ( t
->base
.dirty_images
[0] ) {
520 /* FIXME: For Radeon, RADEON_FIREVERTICES is called here. Should
521 * FIXME: something similar be done for R128?
523 /* FLUSH_BATCH( rmesa ); */
525 r128SetTexImages( rmesa
, tObj
);
526 r128UploadTexImages( rmesa
, t
);
527 if ( !t
->base
.memBlock
)
534 static GLboolean
update_tex_common( GLcontext
*ctx
, int unit
)
536 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
537 const int source
= rmesa
->tmu_source
[unit
];
538 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
539 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
540 r128TexObjPtr t
= (r128TexObjPtr
) tObj
->DriverData
;
543 /* Fallback if there's a texture border */
544 if ( tObj
->Image
[tObj
->BaseLevel
]->Border
> 0 ) {
549 /* Update state if this is a different texture object to last
552 if ( rmesa
->CurrentTexObj
[unit
] != t
) {
553 if ( rmesa
->CurrentTexObj
[unit
] != NULL
) {
554 /* The old texture is no longer bound to this texture unit.
558 rmesa
->CurrentTexObj
[unit
]->base
.bound
&=
562 rmesa
->CurrentTexObj
[unit
] = t
;
563 t
->base
.bound
|= (1UL << unit
);
564 rmesa
->dirty
|= R128_UPLOAD_TEX0
<< unit
;
566 driUpdateTextureLRU( (driTextureObject
*) t
); /* XXX: should be locked! */
569 /* FIXME: We need to update the texture unit if any texture parameters have
570 * changed, but this texture was already bound. This could be changed to
571 * work like the Radeon driver where the texture object has it's own
574 rmesa
->dirty
|= R128_UPLOAD_TEX0
<< unit
;
577 rmesa
->setup
.tex_size_pitch_c
&= ~(R128_TEX_SIZE_PITCH_MASK
<<
578 (R128_SEC_TEX_SIZE_PITCH_SHIFT
* unit
));
581 rmesa
->setup
.tex_cntl_c
|= R128_TEXMAP_ENABLE
;
582 rmesa
->setup
.tex_size_pitch_c
|= t
->setup
.tex_size_pitch
<< 0;
583 rmesa
->setup
.scale_3d_cntl
&= ~R128_TEX_CACHE_SPLIT
;
584 t
->setup
.tex_cntl
&= ~R128_SEC_SELECT_SEC_ST
;
587 rmesa
->setup
.tex_cntl_c
|= R128_SEC_TEXMAP_ENABLE
;
588 rmesa
->setup
.tex_size_pitch_c
|= t
->setup
.tex_size_pitch
<< 16;
589 rmesa
->setup
.scale_3d_cntl
|= R128_TEX_CACHE_SPLIT
;
590 t
->setup
.tex_cntl
|= R128_SEC_SELECT_SEC_ST
;
592 /* If the second TMU is enabled, then multitexturing is happening.
594 if ( R128_IS_PLAIN( rmesa
) )
595 rmesa
->blend_flags
|= R128_BLEND_MULTITEX
;
598 rmesa
->dirty
|= R128_UPLOAD_CONTEXT
;
601 /* FIXME: The Radeon has some cached state so that it can avoid calling
602 * FIXME: UpdateTextureEnv in some cases. Is that possible here?
604 return r128UpdateTextureEnv( ctx
, unit
);
607 static GLboolean
updateTextureUnit( GLcontext
*ctx
, int unit
)
609 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
610 const int source
= rmesa
->tmu_source
[unit
];
611 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
614 if (texUnit
->_ReallyEnabled
& (TEXTURE_1D_BIT
| TEXTURE_2D_BIT
)) {
615 return (enable_tex_2d( ctx
, unit
) &&
616 update_tex_common( ctx
, unit
));
618 else if ( texUnit
->_ReallyEnabled
) {
622 disable_tex( ctx
, unit
);
628 void r128UpdateTextureState( GLcontext
*ctx
)
630 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
634 /* This works around a quirk with the R128 hardware. If only OpenGL
635 * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The
636 * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used.
639 rmesa
->tmu_source
[0] = 0;
640 rmesa
->tmu_source
[1] = 1;
642 if ((ctx
->Texture
._EnabledUnits
& 0x03) == 0x02) {
643 /* only texture 1 enabled */
644 rmesa
->tmu_source
[0] = 1;
645 rmesa
->tmu_source
[1] = 0;
648 ok
= (updateTextureUnit( ctx
, 0 ) &&
649 updateTextureUnit( ctx
, 1 ));
651 FALLBACK( rmesa
, R128_FALLBACK_TEXTURE
, !ok
);