1 /**************************************************************************
3 Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc.,
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, PRECISION INSIGHT 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 **************************************************************************/
30 * Gareth Hughes <gareth@valinux.com>
31 * Kevin E. Martin <martin@valinux.com>
32 * Brian Paul <brianp@valinux.com>
35 #include "main/glheader.h"
36 #include "main/imports.h"
37 #include "main/context.h"
38 #include "main/macros.h"
39 #include "main/texformat.h"
41 #include "r128_context.h"
42 #include "r128_state.h"
43 #include "r128_ioctl.h"
44 #include "r128_tris.h"
48 static void r128SetTexImages( r128ContextPtr rmesa
,
49 const struct gl_texture_object
*tObj
)
51 r128TexObjPtr t
= (r128TexObjPtr
) tObj
->DriverData
;
52 struct gl_texture_image
*baseImage
= tObj
->Image
[0][tObj
->BaseLevel
];
53 int log2Pitch
, log2Height
, log2Size
, log2MinSize
;
56 GLint firstLevel
, lastLevel
;
61 if ( R128_DEBUG
& DEBUG_VERBOSE_API
)
62 fprintf( stderr
, "%s( %p )\n", __FUNCTION__
, (void *) tObj
);
64 switch (baseImage
->TexFormat
->MesaFormat
) {
65 case MESA_FORMAT_ARGB8888
:
66 case MESA_FORMAT_ARGB8888_REV
:
67 t
->textureFormat
= R128_DATATYPE_ARGB8888
;
69 case MESA_FORMAT_ARGB4444
:
70 case MESA_FORMAT_ARGB4444_REV
:
71 t
->textureFormat
= R128_DATATYPE_ARGB4444
;
73 case MESA_FORMAT_RGB565
:
74 case MESA_FORMAT_RGB565_REV
:
75 t
->textureFormat
= R128_DATATYPE_RGB565
;
77 case MESA_FORMAT_RGB332
:
78 t
->textureFormat
= R128_DATATYPE_RGB8
;
81 t
->textureFormat
= R128_DATATYPE_CI8
;
83 case MESA_FORMAT_YCBCR
:
84 t
->textureFormat
= R128_DATATYPE_YVYU422
;
86 case MESA_FORMAT_YCBCR_REV
:
87 t
->textureFormat
= R128_DATATYPE_VYUY422
;
90 _mesa_problem(rmesa
->glCtx
, "Bad texture format in %s", __FUNCTION__
);
93 /* Compute which mipmap levels we really want to send to the hardware.
96 driCalculateTextureFirstLastLevel( (driTextureObject
*) t
);
97 firstLevel
= t
->base
.firstLevel
;
98 lastLevel
= t
->base
.lastLevel
;
100 log2Pitch
= tObj
->Image
[0][firstLevel
]->WidthLog2
;
101 log2Height
= tObj
->Image
[0][firstLevel
]->HeightLog2
;
102 log2Size
= MAX2(log2Pitch
, log2Height
);
103 log2MinSize
= log2Size
;
105 t
->base
.dirty_images
[0] = 0;
107 for ( i
= firstLevel
; i
<= lastLevel
; i
++ ) {
108 const struct gl_texture_image
*texImage
;
110 texImage
= tObj
->Image
[0][i
];
111 if ( !texImage
|| !texImage
->Data
) {
116 log2MinSize
= texImage
->MaxLog2
;
118 t
->image
[i
- firstLevel
].offset
= totalSize
;
119 t
->image
[i
- firstLevel
].width
= tObj
->Image
[0][i
]->Width
;
120 t
->image
[i
- firstLevel
].height
= tObj
->Image
[0][i
]->Height
;
122 t
->base
.dirty_images
[0] |= (1 << i
);
124 totalSize
+= (tObj
->Image
[0][i
]->Height
*
125 tObj
->Image
[0][i
]->Width
*
126 tObj
->Image
[0][i
]->TexFormat
->TexelBytes
);
128 /* Offsets must be 32-byte aligned for host data blits and tiling */
129 totalSize
= (totalSize
+ 31) & ~31;
132 t
->base
.totalSize
= totalSize
;
133 t
->base
.firstLevel
= firstLevel
;
134 t
->base
.lastLevel
= lastLevel
;
136 /* Set the texture format */
137 t
->setup
.tex_cntl
&= ~(0xf << 16);
138 t
->setup
.tex_cntl
|= t
->textureFormat
;
140 t
->setup
.tex_combine_cntl
= 0x00000000; /* XXX is this right? */
142 t
->setup
.tex_size_pitch
= ((log2Pitch
<< R128_TEX_PITCH_SHIFT
) |
143 (log2Size
<< R128_TEX_SIZE_SHIFT
) |
144 (log2Height
<< R128_TEX_HEIGHT_SHIFT
) |
145 (log2MinSize
<< R128_TEX_MIN_SIZE_SHIFT
));
147 for ( i
= 0 ; i
< R128_MAX_TEXTURE_LEVELS
; i
++ ) {
148 t
->setup
.tex_offset
[i
] = 0x00000000;
151 if (firstLevel
== lastLevel
)
152 t
->setup
.tex_cntl
|= R128_MIP_MAP_DISABLE
;
154 t
->setup
.tex_cntl
&= ~R128_MIP_MAP_DISABLE
;
156 /* FYI: r128UploadTexImages( rmesa, t ); used to be called here */
160 /* ================================================================
161 * Texture combine functions
164 #define COLOR_COMB_DISABLE (R128_COMB_DIS | \
165 R128_COLOR_FACTOR_TEX)
166 #define COLOR_COMB_COPY_INPUT (R128_COMB_COPY_INP | \
167 R128_COLOR_FACTOR_TEX)
168 #define COLOR_COMB_MODULATE (R128_COMB_MODULATE | \
169 R128_COLOR_FACTOR_TEX)
170 #define COLOR_COMB_MODULATE_NTEX (R128_COMB_MODULATE | \
171 R128_COLOR_FACTOR_NTEX)
172 #define COLOR_COMB_ADD (R128_COMB_ADD | \
173 R128_COLOR_FACTOR_TEX)
174 #define COLOR_COMB_BLEND_TEX (R128_COMB_BLEND_TEXTURE | \
175 R128_COLOR_FACTOR_TEX)
176 /* Rage 128 Pro/M3 only! */
177 #define COLOR_COMB_BLEND_COLOR (R128_COMB_MODULATE2X | \
178 R128_COMB_FCN_MSB | \
179 R128_COLOR_FACTOR_CONST_COLOR)
181 #define ALPHA_COMB_DISABLE (R128_COMB_ALPHA_DIS | \
182 R128_ALPHA_FACTOR_TEX_ALPHA)
183 #define ALPHA_COMB_COPY_INPUT (R128_COMB_ALPHA_COPY_INP | \
184 R128_ALPHA_FACTOR_TEX_ALPHA)
185 #define ALPHA_COMB_MODULATE (R128_COMB_ALPHA_MODULATE | \
186 R128_ALPHA_FACTOR_TEX_ALPHA)
187 #define ALPHA_COMB_MODULATE_NTEX (R128_COMB_ALPHA_MODULATE | \
188 R128_ALPHA_FACTOR_NTEX_ALPHA)
189 #define ALPHA_COMB_ADD (R128_COMB_ALPHA_ADD | \
190 R128_ALPHA_FACTOR_TEX_ALPHA)
192 #define INPUT_INTERP (R128_INPUT_FACTOR_INT_COLOR | \
193 R128_INP_FACTOR_A_INT_ALPHA)
194 #define INPUT_PREVIOUS (R128_INPUT_FACTOR_PREV_COLOR | \
195 R128_INP_FACTOR_A_PREV_ALPHA)
197 static GLboolean
r128UpdateTextureEnv( GLcontext
*ctx
, int unit
)
199 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
200 GLint source
= rmesa
->tmu_source
[unit
];
201 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
202 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
203 const GLenum format
= tObj
->Image
[0][tObj
->BaseLevel
]->_BaseFormat
;
206 if ( R128_DEBUG
& DEBUG_VERBOSE_API
) {
207 fprintf( stderr
, "%s( %p, %d )\n",
208 __FUNCTION__
, (void *) ctx
, unit
);
212 combine
= INPUT_INTERP
;
214 combine
= INPUT_PREVIOUS
;
217 /* Set the texture environment state */
218 switch ( texUnit
->EnvMode
) {
222 case GL_LUMINANCE_ALPHA
:
224 combine
|= (COLOR_COMB_DISABLE
| /* C = Ct */
225 ALPHA_COMB_DISABLE
); /* A = At */
229 combine
|= (COLOR_COMB_DISABLE
| /* C = Ct */
230 ALPHA_COMB_COPY_INPUT
); /* A = Af */
233 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
234 ALPHA_COMB_DISABLE
); /* A = At */
245 case GL_LUMINANCE_ALPHA
:
247 combine
|= (COLOR_COMB_MODULATE
| /* C = CfCt */
248 ALPHA_COMB_MODULATE
); /* A = AfAt */
252 combine
|= (COLOR_COMB_MODULATE
| /* C = CfCt */
253 ALPHA_COMB_COPY_INPUT
); /* A = Af */
256 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
257 ALPHA_COMB_MODULATE
); /* A = AfAt */
268 combine
|= (COLOR_COMB_BLEND_TEX
| /* C = Cf(1-At)+CtAt */
269 ALPHA_COMB_COPY_INPUT
); /* A = Af */
272 combine
|= (COLOR_COMB_DISABLE
| /* C = Ct */
273 ALPHA_COMB_COPY_INPUT
); /* A = Af */
277 case GL_LUMINANCE_ALPHA
:
279 /* Undefined behaviour - just copy the incoming fragment */
280 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = undefined */
281 ALPHA_COMB_COPY_INPUT
); /* A = undefined */
290 /* Rage 128 Pro and M3 can handle GL_BLEND texturing.
292 if ( !R128_IS_PLAIN( rmesa
) ) {
293 /* XXX this hasn't been fully tested, I don't have a Pro card. -BP */
296 case GL_LUMINANCE_ALPHA
:
297 combine
|= (COLOR_COMB_BLEND_COLOR
| /* C = Cf(1-Ct)+CcCt */
298 ALPHA_COMB_MODULATE
); /* A = AfAt */
303 combine
|= (COLOR_COMB_BLEND_COLOR
| /* C = Cf(1-Ct)+CcCt */
304 ALPHA_COMB_COPY_INPUT
); /* A = Af */
308 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
309 ALPHA_COMB_MODULATE
); /* A = AfAt */
313 /* GH: We could be smarter about this... */
314 switch ( rmesa
->env_color
& 0xff000000 ) {
316 combine
|= (COLOR_COMB_BLEND_COLOR
| /* C = Cf(1-It)+CcIt */
317 ALPHA_COMB_MODULATE_NTEX
); /* A = Af(1-It) */
319 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
320 ALPHA_COMB_MODULATE
); /* A = fallback */
332 /* Rage 128 has to fake some cases of GL_BLEND, otherwise fallback
333 * to software rendering.
335 if ( rmesa
->blend_flags
) {
340 case GL_LUMINANCE_ALPHA
:
341 switch ( rmesa
->env_color
& 0x00ffffff ) {
343 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
344 ALPHA_COMB_MODULATE
); /* A = AfAt */
347 /* This isn't right - BP */
350 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
351 ALPHA_COMB_MODULATE
); /* A = AfAt */
353 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
354 ALPHA_COMB_COPY_INPUT
); /* A = Af */
359 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
360 ALPHA_COMB_MODULATE
); /* A = fallback */
366 switch ( rmesa
->env_color
& 0x00ffffff ) {
368 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
369 ALPHA_COMB_COPY_INPUT
); /* A = Af */
372 /* This isn't right - BP */
375 combine
|= (COLOR_COMB_MODULATE_NTEX
| /* C = Cf(1-Ct) */
376 ALPHA_COMB_COPY_INPUT
); /* A = Af */
378 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
379 ALPHA_COMB_COPY_INPUT
); /* A = Af */
384 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
385 ALPHA_COMB_COPY_INPUT
); /* A = fallback */
391 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
392 ALPHA_COMB_MODULATE
); /* A = AfAt */
394 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
395 ALPHA_COMB_COPY_INPUT
); /* A = Af */
399 switch ( rmesa
->env_color
& 0x00ffffff ) {
401 combine
|= COLOR_COMB_MODULATE_NTEX
; /* C = Cf(1-It) */
404 /* This isn't right - BP */
407 combine
|= COLOR_COMB_MODULATE_NTEX
; /* C = Cf(1-It) */
409 combine
|= COLOR_COMB_ADD
; /* C = Cf+It */
414 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
415 ALPHA_COMB_MODULATE
); /* A = fallback */
418 switch ( rmesa
->env_color
& 0xff000000 ) {
420 combine
|= ALPHA_COMB_MODULATE_NTEX
; /* A = Af(1-It) */
423 /* This isn't right - BP */
426 combine
|= ALPHA_COMB_MODULATE_NTEX
; /* A = Af(1-It) */
428 combine
|= ALPHA_COMB_ADD
; /* A = Af+It */
433 combine
|= (COLOR_COMB_MODULATE
| /* C = fallback */
434 ALPHA_COMB_MODULATE
); /* A = fallback */
447 case GL_LUMINANCE_ALPHA
:
448 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
449 ALPHA_COMB_MODULATE
); /* A = AfAt */
453 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
454 ALPHA_COMB_COPY_INPUT
); /* A = Af */
457 combine
|= (COLOR_COMB_COPY_INPUT
| /* C = Cf */
458 ALPHA_COMB_MODULATE
); /* A = AfAt */
461 combine
|= (COLOR_COMB_ADD
| /* C = Cf+Ct */
462 ALPHA_COMB_ADD
); /* A = Af+At */
474 if ( rmesa
->tex_combine
[unit
] != combine
) {
475 rmesa
->tex_combine
[unit
] = combine
;
476 rmesa
->dirty
|= R128_UPLOAD_TEX0
<< unit
;
481 static void disable_tex( GLcontext
*ctx
, int unit
)
483 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
485 FLUSH_BATCH( rmesa
);
487 if ( rmesa
->CurrentTexObj
[unit
] ) {
488 rmesa
->CurrentTexObj
[unit
]->base
.bound
&= ~(1 << unit
);
489 rmesa
->CurrentTexObj
[unit
] = NULL
;
492 rmesa
->setup
.tex_cntl_c
&= ~(R128_TEXMAP_ENABLE
<< unit
);
493 rmesa
->setup
.tex_size_pitch_c
&= ~(R128_TEX_SIZE_PITCH_MASK
<<
494 (R128_SEC_TEX_SIZE_PITCH_SHIFT
* unit
));
495 rmesa
->dirty
|= R128_UPLOAD_CONTEXT
;
497 /* If either texture unit is disabled, then multitexturing is not
501 rmesa
->blend_flags
&= ~R128_BLEND_MULTITEX
;
504 static GLboolean
enable_tex_2d( GLcontext
*ctx
, int unit
)
506 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
507 const int source
= rmesa
->tmu_source
[unit
];
508 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
509 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
510 r128TexObjPtr t
= (r128TexObjPtr
) tObj
->DriverData
;
512 /* Need to load the 2d images associated with this unit.
514 if ( t
->base
.dirty_images
[0] ) {
515 /* FIXME: For Radeon, RADEON_FIREVERTICES is called here. Should
516 * FIXME: something similar be done for R128?
518 /* FLUSH_BATCH( rmesa ); */
520 r128SetTexImages( rmesa
, tObj
);
521 r128UploadTexImages( rmesa
, t
);
522 if ( !t
->base
.memBlock
)
529 static GLboolean
update_tex_common( GLcontext
*ctx
, int unit
)
531 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
532 const int source
= rmesa
->tmu_source
[unit
];
533 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
534 const struct gl_texture_object
*tObj
= texUnit
->_Current
;
535 r128TexObjPtr t
= (r128TexObjPtr
) tObj
->DriverData
;
538 /* Fallback if there's a texture border */
539 if ( tObj
->Image
[0][tObj
->BaseLevel
]->Border
> 0 ) {
544 /* Update state if this is a different texture object to last
547 if ( rmesa
->CurrentTexObj
[unit
] != t
) {
548 if ( rmesa
->CurrentTexObj
[unit
] != NULL
) {
549 /* The old texture is no longer bound to this texture unit.
553 rmesa
->CurrentTexObj
[unit
]->base
.bound
&=
557 rmesa
->CurrentTexObj
[unit
] = t
;
558 t
->base
.bound
|= (1UL << unit
);
559 rmesa
->dirty
|= R128_UPLOAD_TEX0
<< unit
;
561 driUpdateTextureLRU( (driTextureObject
*) t
); /* XXX: should be locked! */
564 /* FIXME: We need to update the texture unit if any texture parameters have
565 * changed, but this texture was already bound. This could be changed to
566 * work like the Radeon driver where the texture object has it's own
569 rmesa
->dirty
|= R128_UPLOAD_TEX0
<< unit
;
572 rmesa
->setup
.tex_size_pitch_c
&= ~(R128_TEX_SIZE_PITCH_MASK
<<
573 (R128_SEC_TEX_SIZE_PITCH_SHIFT
* unit
));
576 rmesa
->setup
.tex_cntl_c
|= R128_TEXMAP_ENABLE
;
577 rmesa
->setup
.tex_size_pitch_c
|= t
->setup
.tex_size_pitch
<< 0;
578 rmesa
->setup
.scale_3d_cntl
&= ~R128_TEX_CACHE_SPLIT
;
579 t
->setup
.tex_cntl
&= ~R128_SEC_SELECT_SEC_ST
;
582 rmesa
->setup
.tex_cntl_c
|= R128_SEC_TEXMAP_ENABLE
;
583 rmesa
->setup
.tex_size_pitch_c
|= t
->setup
.tex_size_pitch
<< 16;
584 rmesa
->setup
.scale_3d_cntl
|= R128_TEX_CACHE_SPLIT
;
585 t
->setup
.tex_cntl
|= R128_SEC_SELECT_SEC_ST
;
587 /* If the second TMU is enabled, then multitexturing is happening.
589 if ( R128_IS_PLAIN( rmesa
) )
590 rmesa
->blend_flags
|= R128_BLEND_MULTITEX
;
593 rmesa
->dirty
|= R128_UPLOAD_CONTEXT
;
596 /* FIXME: The Radeon has some cached state so that it can avoid calling
597 * FIXME: UpdateTextureEnv in some cases. Is that possible here?
599 return r128UpdateTextureEnv( ctx
, unit
);
602 static GLboolean
updateTextureUnit( GLcontext
*ctx
, int unit
)
604 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
605 const int source
= rmesa
->tmu_source
[unit
];
606 const struct gl_texture_unit
*texUnit
= &ctx
->Texture
.Unit
[source
];
609 if (texUnit
->_ReallyEnabled
& (TEXTURE_1D_BIT
| TEXTURE_2D_BIT
)) {
610 return (enable_tex_2d( ctx
, unit
) &&
611 update_tex_common( ctx
, unit
));
613 else if ( texUnit
->_ReallyEnabled
) {
617 disable_tex( ctx
, unit
);
623 void r128UpdateTextureState( GLcontext
*ctx
)
625 r128ContextPtr rmesa
= R128_CONTEXT(ctx
);
629 /* This works around a quirk with the R128 hardware. If only OpenGL
630 * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The
631 * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used.
634 rmesa
->tmu_source
[0] = 0;
635 rmesa
->tmu_source
[1] = 1;
637 if ((ctx
->Texture
._EnabledUnits
& 0x03) == 0x02) {
638 /* only texture 1 enabled */
639 rmesa
->tmu_source
[0] = 1;
640 rmesa
->tmu_source
[1] = 0;
643 ok
= (updateTextureUnit( ctx
, 0 ) &&
644 updateTextureUnit( ctx
, 1 ));
646 FALLBACK( rmesa
, R128_FALLBACK_TEXTURE
, !ok
);