summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/tdfx/tdfx_texstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/tdfx/tdfx_texstate.c')
-rw-r--r--src/mesa/drivers/dri/tdfx/tdfx_texstate.c2107
1 files changed, 2107 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/tdfx/tdfx_texstate.c b/src/mesa/drivers/dri/tdfx/tdfx_texstate.c
new file mode 100644
index 0000000000..e20938bf28
--- /dev/null
+++ b/src/mesa/drivers/dri/tdfx/tdfx_texstate.c
@@ -0,0 +1,2107 @@
+/* -*- mode: c; c-basic-offset: 3 -*-
+ *
+ * Copyright 2000 VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $XFree86: xc/lib/GL/mesa/src/drv/tdfx/tdfx_texstate.c,v 1.2 2002/02/22 21:45:04 dawes Exp $ */
+
+/*
+ * Original rewrite:
+ * Gareth Hughes <gareth@valinux.com>, 29 Sep - 1 Oct 2000
+ *
+ * Authors:
+ * Gareth Hughes <gareth@valinux.com>
+ * Brian Paul <brianp@valinux.com>
+ *
+ */
+
+#include "tdfx_state.h"
+#include "tdfx_tex.h"
+#include "tdfx_texman.h"
+#include "tdfx_texstate.h"
+
+
+/* =============================================================
+ * Texture
+ */
+
+/*
+ * These macros are used below when handling COMBINE_EXT.
+ */
+#define TEXENV_OPERAND_INVERTED(operand) \
+ (((operand) == GL_ONE_MINUS_SRC_ALPHA) \
+ || ((operand) == GL_ONE_MINUS_SRC_COLOR))
+#define TEXENV_OPERAND_ALPHA(operand) \
+ (((operand) == GL_SRC_ALPHA) || ((operand) == GL_ONE_MINUS_SRC_ALPHA))
+#define TEXENV_SETUP_ARG_A(param, source, operand, iteratedAlpha) \
+ switch (source) { \
+ case GL_TEXTURE: \
+ param = GR_CMBX_LOCAL_TEXTURE_ALPHA; \
+ break; \
+ case GL_CONSTANT_EXT: \
+ param = GR_CMBX_TMU_CALPHA; \
+ break; \
+ case GL_PRIMARY_COLOR_EXT: \
+ param = GR_CMBX_ITALPHA; \
+ break; \
+ case GL_PREVIOUS_EXT: \
+ param = iteratedAlpha; \
+ break; \
+ default: \
+ /* \
+ * This is here just to keep from getting \
+ * compiler warnings. \
+ */ \
+ param = GR_CMBX_ZERO; \
+ break; \
+ }
+
+#define TEXENV_SETUP_ARG_RGB(param, source, operand, iteratedColor, iteratedAlpha) \
+ if (!TEXENV_OPERAND_ALPHA(operand)) { \
+ switch (source) { \
+ case GL_TEXTURE: \
+ param = GR_CMBX_LOCAL_TEXTURE_RGB; \
+ break; \
+ case GL_CONSTANT_EXT: \
+ param = GR_CMBX_TMU_CCOLOR; \
+ break; \
+ case GL_PRIMARY_COLOR_EXT: \
+ param = GR_CMBX_ITRGB; \
+ break; \
+ case GL_PREVIOUS_EXT: \
+ param = iteratedColor; \
+ break; \
+ default: \
+ /* \
+ * This is here just to keep from getting \
+ * compiler warnings. \
+ */ \
+ param = GR_CMBX_ZERO; \
+ break; \
+ } \
+ } else { \
+ switch (source) { \
+ case GL_TEXTURE: \
+ param = GR_CMBX_LOCAL_TEXTURE_ALPHA; \
+ break; \
+ case GL_CONSTANT_EXT: \
+ param = GR_CMBX_TMU_CALPHA; \
+ break; \
+ case GL_PRIMARY_COLOR_EXT: \
+ param = GR_CMBX_ITALPHA; \
+ break; \
+ case GL_PREVIOUS_EXT: \
+ param = iteratedAlpha; \
+ break; \
+ default: \
+ /* \
+ * This is here just to keep from getting \
+ * compiler warnings. \
+ */ \
+ param = GR_CMBX_ZERO; \
+ break; \
+ } \
+ }
+
+#define TEXENV_SETUP_MODE_RGB(param, operand) \
+ switch (operand) { \
+ case GL_SRC_COLOR: \
+ case GL_SRC_ALPHA: \
+ param = GR_FUNC_MODE_X; \
+ break; \
+ case GL_ONE_MINUS_SRC_ALPHA: \
+ case GL_ONE_MINUS_SRC_COLOR: \
+ param = GR_FUNC_MODE_ONE_MINUS_X; \
+ break; \
+ default: \
+ param = GR_FUNC_MODE_ZERO; \
+ break; \
+ }
+
+#define TEXENV_SETUP_MODE_A(param, operand) \
+ switch (operand) { \
+ case GL_SRC_ALPHA: \
+ param = GR_FUNC_MODE_X; \
+ break; \
+ case GL_ONE_MINUS_SRC_ALPHA: \
+ param = GR_FUNC_MODE_ONE_MINUS_X; \
+ break; \
+ default: \
+ param = GR_FUNC_MODE_ZERO; \
+ break; \
+ }
+
+
+
+/*
+ * Setup a texture environment on Voodoo5.
+ * Return GL_TRUE for success, GL_FALSE for failure.
+ * If we fail, we'll have to use software rendering.
+ */
+static GLboolean
+SetupTexEnvNapalm(GLcontext *ctx, GLboolean useIteratedRGBA,
+ const struct gl_texture_unit *texUnit, GLenum baseFormat,
+ struct tdfx_texcombine_ext *env)
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+ GrTCCUColor_t incomingRGB, incomingAlpha;
+ const GLenum envMode = texUnit->EnvMode;
+
+ if (useIteratedRGBA) {
+ incomingRGB = GR_CMBX_ITRGB;
+ incomingAlpha = GR_CMBX_ITALPHA;
+ }
+ else {
+ incomingRGB = GR_CMBX_OTHER_TEXTURE_RGB;
+ incomingAlpha = GR_CMBX_OTHER_TEXTURE_ALPHA;
+ }
+
+ /* invariant: */
+ env->Color.Shift = 0;
+ env->Color.Invert = FXFALSE;
+ env->Alpha.Shift = 0;
+ env->Alpha.Invert = FXFALSE;
+
+ switch (envMode) {
+ case GL_REPLACE:
+ /* -- Setup RGB combiner */
+ if (baseFormat == GL_ALPHA) {
+ /* Rv = Rf */
+ env->Color.SourceA = incomingRGB;
+ }
+ else {
+ /* Rv = Rt */
+ env->Color.SourceA = GR_CMBX_LOCAL_TEXTURE_RGB;
+ }
+ env->Color.ModeA = GR_FUNC_MODE_X;
+ env->Color.SourceB = GR_CMBX_ZERO;
+ env->Color.ModeB = GR_FUNC_MODE_ZERO;
+ env->Color.SourceC = GR_CMBX_ZERO;
+ env->Color.InvertC = FXTRUE;
+ env->Color.SourceD = GR_CMBX_ZERO;
+ env->Color.InvertD = FXFALSE;
+ /* -- Setup Alpha combiner */
+ if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+ /* Av = Af */
+ env->Alpha.SourceD = incomingAlpha;
+ }
+ else {
+ /* Av = At */
+ env->Alpha.SourceD = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ }
+ env->Alpha.SourceA = GR_CMBX_ITALPHA;
+ env->Alpha.ModeA = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceB = GR_CMBX_ITALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceC = GR_CMBX_ZERO;
+ env->Alpha.InvertC = FXFALSE;
+ env->Alpha.InvertD = FXFALSE;
+ break;
+
+ case GL_MODULATE:
+ /* -- Setup RGB combiner */
+ if (baseFormat == GL_ALPHA) {
+ /* Rv = Rf */
+ env->Color.SourceC = GR_CMBX_ZERO;
+ env->Color.InvertC = FXTRUE;
+ }
+ else {
+ /* Result = Frag * Tex */
+ env->Color.SourceC = GR_CMBX_LOCAL_TEXTURE_RGB;
+ env->Color.InvertC = FXFALSE;
+ }
+ env->Color.SourceA = incomingRGB;
+ env->Color.ModeA = GR_FUNC_MODE_X;
+ env->Color.SourceB = GR_CMBX_ZERO;
+ env->Color.ModeB = GR_FUNC_MODE_ZERO;
+ env->Color.SourceD = GR_CMBX_ZERO;
+ env->Color.InvertD = FXFALSE;
+ /* -- Setup Alpha combiner */
+ if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+ /* Av = Af */
+ env->Alpha.SourceA = incomingAlpha;
+ env->Alpha.SourceC = GR_CMBX_ZERO;
+ env->Alpha.InvertC = FXTRUE;
+ }
+ else {
+ /* Av = Af * At */
+ env->Alpha.SourceA = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ env->Alpha.SourceC = incomingAlpha;
+ env->Alpha.InvertC = FXFALSE;
+ }
+ env->Alpha.ModeA = GR_FUNC_MODE_X;
+ env->Alpha.SourceB = GR_CMBX_ITALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceD = GR_CMBX_ZERO;
+ env->Alpha.InvertD = FXFALSE;
+ break;
+
+ case GL_DECAL:
+ /* -- Setup RGB combiner */
+ if (baseFormat == GL_RGB) {
+ /* Rv = Rt */
+ env->Color.SourceB = GR_CMBX_ZERO;
+ env->Color.ModeB = GR_FUNC_MODE_X;
+ env->Color.SourceC = GR_CMBX_ZERO;
+ env->Color.InvertC = FXTRUE;
+ env->Color.SourceD = GR_CMBX_ZERO;
+ env->Color.InvertD = FXFALSE;
+ }
+ else {
+ /* Rv = Rf * (1 - At) + Rt * At */
+ env->Color.SourceB = incomingRGB;
+ env->Color.ModeB = GR_FUNC_MODE_NEGATIVE_X;
+ env->Color.SourceC = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ env->Color.InvertC = FXFALSE;
+ env->Color.SourceD = GR_CMBX_B;
+ env->Color.InvertD = FXFALSE;
+ }
+ env->Color.SourceA = GR_CMBX_LOCAL_TEXTURE_RGB;
+ env->Color.ModeA = GR_FUNC_MODE_X;
+ /* -- Setup Alpha combiner */
+ /* Av = Af */
+ env->Alpha.SourceA = incomingAlpha;
+ env->Alpha.ModeA = GR_FUNC_MODE_X;
+ env->Alpha.SourceB = GR_CMBX_ITALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceC = GR_CMBX_ZERO;
+ env->Alpha.InvertC = FXTRUE;
+ env->Alpha.SourceD = GR_CMBX_ZERO;
+ env->Alpha.InvertD = FXFALSE;
+ break;
+
+ case GL_BLEND:
+ /* -- Setup RGB combiner */
+ if (baseFormat == GL_ALPHA) {
+ /* Rv = Rf */
+ env->Color.SourceA = incomingRGB;
+ env->Color.ModeA = GR_FUNC_MODE_X;
+ env->Color.SourceB = GR_CMBX_ZERO;
+ env->Color.ModeB = GR_FUNC_MODE_ZERO;
+ env->Color.SourceC = GR_CMBX_ZERO;
+ env->Color.InvertC = FXTRUE;
+ env->Color.SourceD = GR_CMBX_ZERO;
+ env->Color.InvertD = FXFALSE;
+ }
+ else {
+ /* Rv = Rf * (1 - Rt) + Rc * Rt */
+ env->Color.SourceA = GR_CMBX_TMU_CCOLOR;
+ env->Color.ModeA = GR_FUNC_MODE_X;
+ env->Color.SourceB = incomingRGB;
+ env->Color.ModeB = GR_FUNC_MODE_NEGATIVE_X;
+ env->Color.SourceC = GR_CMBX_LOCAL_TEXTURE_RGB;
+ env->Color.InvertC = FXFALSE;
+ env->Color.SourceD = GR_CMBX_B;
+ env->Color.InvertD = FXFALSE;
+ }
+ /* -- Setup Alpha combiner */
+ if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+ /* Av = Af */
+ env->Alpha.SourceA = incomingAlpha;
+ env->Alpha.ModeA = GR_FUNC_MODE_X;
+ env->Alpha.SourceB = GR_CMBX_ZERO;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceC = GR_CMBX_ZERO;
+ env->Alpha.InvertC = FXTRUE;
+ env->Alpha.SourceD = GR_CMBX_ZERO;
+ env->Alpha.InvertD = FXFALSE;
+ }
+ else if (baseFormat == GL_INTENSITY) {
+ /* Av = Af * (1 - It) + Ac * It */
+ env->Alpha.SourceA = GR_CMBX_TMU_CALPHA;
+ env->Alpha.ModeA = GR_FUNC_MODE_X;
+ env->Alpha.SourceB = incomingAlpha;
+ env->Alpha.ModeB = GR_FUNC_MODE_NEGATIVE_X;
+ env->Alpha.SourceC = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ env->Alpha.InvertC = FXFALSE;
+ env->Alpha.SourceD = GR_CMBX_B;
+ env->Alpha.InvertD = FXFALSE;
+ }
+ else {
+ /* Av = Af * At */
+ env->Alpha.SourceA = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ env->Alpha.ModeA = GR_FUNC_MODE_X;
+ env->Alpha.SourceB = GR_CMBX_ITALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceC = incomingAlpha;
+ env->Alpha.InvertC = FXFALSE;
+ env->Alpha.SourceD = GR_CMBX_ZERO;
+ env->Alpha.InvertD = FXFALSE;
+ }
+ /* Also have to set up the tex env constant color */
+ env->EnvColor = PACK_RGBA32(texUnit->EnvColor[0] * 255.0F,
+ texUnit->EnvColor[1] * 255.0F,
+ texUnit->EnvColor[2] * 255.0F,
+ texUnit->EnvColor[3] * 255.0F);
+ break;
+ case GL_ADD:
+ /* -- Setup RGB combiner */
+ if (baseFormat == GL_ALPHA) {
+ /* Rv = Rf */
+ env->Color.SourceB = GR_CMBX_ZERO;
+ env->Color.ModeB = GR_FUNC_MODE_ZERO;
+ }
+ else {
+ /* Rv = Rf + Tt */
+ env->Color.SourceB = GR_CMBX_LOCAL_TEXTURE_RGB;
+ env->Color.ModeB = GR_FUNC_MODE_X;
+ }
+ env->Color.SourceA = incomingRGB;
+ env->Color.ModeA = GR_FUNC_MODE_X;
+ env->Color.SourceC = GR_CMBX_ZERO;
+ env->Color.InvertC = FXTRUE;
+ env->Color.SourceD = GR_CMBX_ZERO;
+ env->Color.InvertD = FXFALSE;
+ /* -- Setup Alpha combiner */
+ if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+ /* Av = Af */
+ env->Alpha.SourceA = incomingAlpha;
+ env->Alpha.SourceB = GR_CMBX_ITALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceC = GR_CMBX_ZERO;
+ env->Alpha.InvertC = FXTRUE;
+
+ }
+ else if (baseFormat == GL_INTENSITY) {
+ /* Av = Af + It */
+ env->Alpha.SourceA = incomingAlpha;
+ env->Alpha.SourceB = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_X;
+ env->Alpha.SourceC = GR_CMBX_ZERO;
+ env->Alpha.InvertC = FXTRUE;
+ }
+ else {
+ /* Av = Af * At */
+ env->Alpha.SourceA = GR_CMBX_LOCAL_TEXTURE_ALPHA;
+ env->Alpha.SourceB = GR_CMBX_ITALPHA;
+ env->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ env->Alpha.SourceC = incomingAlpha;
+ env->Alpha.InvertC = FXFALSE;
+ }
+ env->Alpha.ModeA = GR_FUNC_MODE_X;
+ env->Alpha.SourceD = GR_CMBX_ZERO;
+ env->Alpha.InvertD = FXFALSE;
+ break;
+
+ case GL_COMBINE_EXT:
+ {
+ FxU32 A_RGB, B_RGB, C_RGB, D_RGB;
+ FxU32 Amode_RGB, Bmode_RGB;
+ FxBool Cinv_RGB, Dinv_RGB, Ginv_RGB;
+ FxU32 Shift_RGB;
+ FxU32 A_A, B_A, C_A, D_A;
+ FxU32 Amode_A, Bmode_A;
+ FxBool Cinv_A, Dinv_A, Ginv_A;
+ FxU32 Shift_A;
+
+ /*
+ *
+ * In the formulas below, we write:
+ * o "1(x)" for the identity function applied to x,
+ * so 1(x) = x.
+ * o "0(x)" for the constant function 0, so
+ * 0(x) = 0 for all values of x.
+ *
+ * Calculate the color combination.
+ */
+ Shift_RGB = texUnit->CombineScaleShiftRGB;
+ Shift_A = texUnit->CombineScaleShiftA;
+ switch (texUnit->CombineModeRGB) {
+ case GL_REPLACE:
+ /*
+ * The formula is: Arg0
+ * We implement this by the formula:
+ * (Arg0 + 0(0))*(1-0) + 0
+ */
+ TEXENV_SETUP_ARG_RGB(A_RGB,
+ texUnit->CombineSourceRGB[0],
+ texUnit->CombineOperandRGB[0],
+ incomingRGB, incomingAlpha);
+ TEXENV_SETUP_MODE_RGB(Amode_RGB,
+ texUnit->CombineOperandRGB[0]);
+ B_RGB = C_RGB = D_RGB = GR_CMBX_ZERO;
+ Bmode_RGB = GR_FUNC_MODE_ZERO;
+ Cinv_RGB = FXTRUE;
+ Dinv_RGB = Ginv_RGB = FXFALSE;
+ break;
+ case GL_MODULATE:
+ /*
+ * The formula is: Arg0 * Arg1
+ *
+ * We implement this by the formula
+ * (Arg0 + 0(0)) * Arg1 + 0(0)
+ */
+ TEXENV_SETUP_ARG_RGB(A_RGB,
+ texUnit->CombineSourceRGB[0],
+ texUnit->CombineOperandRGB[0],
+ incomingRGB, incomingAlpha);
+ TEXENV_SETUP_MODE_RGB(Amode_RGB,
+ texUnit->CombineOperandRGB[0]);
+ B_RGB = GR_CMBX_ZERO;
+ Bmode_RGB = GR_CMBX_ZERO;
+ TEXENV_SETUP_ARG_RGB(C_RGB,
+ texUnit->CombineSourceRGB[1],
+ texUnit->CombineOperandRGB[1],
+ incomingRGB, incomingAlpha);
+ Cinv_RGB = TEXENV_OPERAND_INVERTED
+ (texUnit->CombineOperandRGB[1]);
+ D_RGB = GR_CMBX_ZERO;
+ Dinv_RGB = Ginv_RGB = FXFALSE;
+ break;
+ case GL_ADD:
+ /*
+ * The formula is Arg0 + Arg1
+ */
+ TEXENV_SETUP_ARG_RGB(A_RGB,
+ texUnit->CombineSourceRGB[0],
+ texUnit->CombineOperandRGB[0],
+ incomingRGB, incomingAlpha);
+ TEXENV_SETUP_MODE_RGB(Amode_RGB,
+ texUnit->CombineOperandRGB[0]);
+ TEXENV_SETUP_ARG_RGB(B_RGB,
+ texUnit->CombineSourceRGB[1],
+ texUnit->CombineOperandRGB[1],
+ incomingRGB, incomingAlpha);
+ TEXENV_SETUP_MODE_RGB(Bmode_RGB,
+ texUnit->CombineOperandRGB[1]);
+ C_RGB = D_RGB = GR_CMBX_ZERO;
+ Cinv_RGB = FXTRUE;
+ Dinv_RGB = Ginv_RGB = FXFALSE;
+ break;
+ case GL_ADD_SIGNED_EXT:
+ /*
+ * The formula is: Arg0 + Arg1 - 0.5.
+ * We compute this by calculating:
+ * (Arg0 - 1/2) + Arg1 if op0 is SRC_{COLOR,ALPHA}
+ * Arg0 + (Arg1 - 1/2) if op1 is SRC_{COLOR,ALPHA}
+ * If both op0 and op1 are ONE_MINUS_SRC_{COLOR,ALPHA}
+ * we cannot implement the formula properly.
+ */
+ TEXENV_SETUP_ARG_RGB(A_RGB,
+ texUnit->CombineSourceRGB[0],
+ texUnit->CombineOperandRGB[0],
+ incomingRGB, incomingAlpha);
+ TEXENV_SETUP_ARG_RGB(B_RGB,
+ texUnit->CombineSourceRGB[1],
+ texUnit->CombineOperandRGB[1],
+ incomingRGB, incomingAlpha);
+ if (!TEXENV_OPERAND_INVERTED(texUnit->CombineOperandRGB[0])) {
+ /*
+ * A is not inverted. So, choose it.
+ */
+ Amode_RGB = GR_FUNC_MODE_X_MINUS_HALF;
+ if (!TEXENV_OPERAND_INVERTED
+ (texUnit->CombineOperandRGB[1])) {
+ Bmode_RGB = GR_FUNC_MODE_X;
+ }
+ else {
+ Bmode_RGB = GR_FUNC_MODE_ONE_MINUS_X;
+ }
+ }
+ else {
+ /*
+ * A is inverted, so try to subtract 1/2
+ * from B.
+ */
+ Amode_RGB = GR_FUNC_MODE_ONE_MINUS_X;
+ if (!TEXENV_OPERAND_INVERTED
+ (texUnit->CombineOperandRGB[1])) {
+ Bmode_RGB = GR_FUNC_MODE_X_MINUS_HALF;
+ }
+ else {
+ /*
+ * Both are inverted. This is the case
+ * we cannot handle properly. We just
+ * choose to not add the - 1/2.
+ */
+ Bmode_RGB = GR_FUNC_MODE_ONE_MINUS_X;
+ return GL_FALSE;
+ }
+ }
+ C_RGB = D_RGB = GR_CMBX_ZERO;
+ Cinv_RGB = FXTRUE;
+ Dinv_RGB = Ginv_RGB = FXFALSE;
+ break;
+ case GL_INTERPOLATE_EXT:
+ /*
+ * The formula is: Arg0 * Arg2 + Arg1 * (1 - Arg2).
+ * We compute this by the formula:
+ * (Arg0 - Arg1) * Arg2 + Arg1
+ * == Arg0 * Arg2 - Arg1 * Arg2 + Arg1
+ * == Arg0 * Arg2 + Arg1 * (1 - Arg2)
+ * However, if both Arg1 is ONE_MINUS_X, the HW does
+ * not support it properly.
+ */
+ TEXENV_SETUP_ARG_RGB(A_RGB,
+ texUnit->CombineSourceRGB[0],
+ texUnit->CombineOperandRGB[0],
+ incomingRGB, incomingAlpha);
+ TEXENV_SETUP_MODE_RGB(Amode_RGB,
+ texUnit->CombineOperandRGB[0]);
+ TEXENV_SETUP_ARG_RGB(B_RGB,
+ texUnit->CombineSourceRGB[1],
+ texUnit->CombineOperandRGB[1],
+ incomingRGB, incomingAlpha);
+ if (TEXENV_OPERAND_INVERTED(texUnit->CombineOperandRGB[1])) {
+ /*
+ * This case is wrong.
+ */
+ Bmode_RGB = GR_FUNC_MODE_NEGATIVE_X;
+ return GL_FALSE;
+ }
+ else {
+ Bmode_RGB = GR_FUNC_MODE_NEGATIVE_X;
+ }
+ /*
+ * The Source/Operand for the C value must
+ * specify some kind of alpha value.
+ */
+ TEXENV_SETUP_ARG_A(C_RGB,
+ texUnit->CombineSourceRGB[2],
+ texUnit->CombineOperandRGB[2],
+ incomingAlpha);
+ Cinv_RGB = FXFALSE;
+ D_RGB = GR_CMBX_B;
+ Dinv_RGB = Ginv_RGB = FXFALSE;
+ break;
+ default:
+ /*
+ * This is here mostly to keep from getting
+ * a compiler warning about these not being set.
+ * However, this should set all the texture values
+ * to zero.
+ */
+ A_RGB = B_RGB = C_RGB = D_RGB = GR_CMBX_ZERO;
+ Amode_RGB = Bmode_RGB = GR_FUNC_MODE_X;
+ Cinv_RGB = Dinv_RGB = Ginv_RGB = FXFALSE;
+ break;
+ }
+ /*
+ * Calculate the alpha combination.
+ */
+ switch (texUnit->CombineModeA) {
+ case GL_REPLACE:
+ /*
+ * The formula is: Arg0
+ * We implement this by the formula:
+ * (Arg0 + 0(0))*(1-0) + 0
+ */
+ TEXENV_SETUP_ARG_A(A_A,
+ texUnit->CombineSourceA[0],
+ texUnit->CombineOperandA[0],
+ incomingAlpha);
+ TEXENV_SETUP_MODE_A(Amode_A,
+ texUnit->CombineOperandA[0]);
+ B_A = GR_CMBX_ITALPHA;
+ Bmode_A = GR_FUNC_MODE_ZERO;
+ C_A = D_A = GR_CMBX_ZERO;
+ Cinv_A = FXTRUE;
+ Dinv_A = Ginv_A = FXFALSE;
+ break;
+ case GL_MODULATE:
+ /*
+ * The formula is: Arg0 * Arg1
+ *
+ * We implement this by the formula
+ * (Arg0 + 0(0)) * Arg1 + 0(0)
+ */
+ TEXENV_SETUP_ARG_A(A_A,
+ texUnit->CombineSourceA[0],
+ texUnit->CombineOperandA[0],
+ incomingAlpha);
+ TEXENV_SETUP_MODE_A(Amode_A,
+ texUnit->CombineOperandA[0]);
+ B_A = GR_CMBX_ZERO;
+ Bmode_A = GR_CMBX_ZERO;
+ TEXENV_SETUP_ARG_A(C_A,
+ texUnit->CombineSourceA[1],
+ texUnit->CombineOperandA[1],
+ incomingAlpha);
+ Cinv_A = TEXENV_OPERAND_INVERTED
+ (texUnit->CombineOperandA[1]);
+ D_A = GR_CMBX_ZERO;
+ Dinv_A = Ginv_A = FXFALSE;
+ break;
+ case GL_ADD:
+ /*
+ * The formula is Arg0 + Arg1
+ */
+ TEXENV_SETUP_ARG_A(A_A,
+ texUnit->CombineSourceA[0],
+ texUnit->CombineOperandA[0],
+ incomingAlpha);
+ TEXENV_SETUP_MODE_A(Amode_A,
+ texUnit->CombineOperandA[0]);
+ TEXENV_SETUP_ARG_A(B_A,
+ texUnit->CombineSourceA[1],
+ texUnit->CombineOperandA[1],
+ incomingAlpha);
+ TEXENV_SETUP_MODE_A(Bmode_A,
+ texUnit->CombineOperandA[1]);
+ C_A = D_A = GR_CMBX_ZERO;
+ Cinv_A = FXTRUE;
+ Dinv_A = Ginv_A = FXFALSE;
+ break;
+ case GL_ADD_SIGNED_EXT:
+ /*
+ * The formula is: Arg0 + Arg1 - 0.5.
+ * We compute this by calculating:
+ * (Arg0 - 1/2) + Arg1 if op0 is SRC_{COLOR,ALPHA}
+ * Arg0 + (Arg1 - 1/2) if op1 is SRC_{COLOR,ALPHA}
+ * If both op0 and op1 are ONE_MINUS_SRC_{COLOR,ALPHA}
+ * we cannot implement the formula properly.
+ */
+ TEXENV_SETUP_ARG_A(A_A,
+ texUnit->CombineSourceA[0],
+ texUnit->CombineOperandA[0],
+ incomingAlpha);
+ TEXENV_SETUP_ARG_A(B_A,
+ texUnit->CombineSourceA[1],
+ texUnit->CombineOperandA[1],
+ incomingAlpha);
+ if (!TEXENV_OPERAND_INVERTED(texUnit->CombineOperandA[0])) {
+ /*
+ * A is not inverted. So, choose it.
+ */
+ Amode_A = GR_FUNC_MODE_X_MINUS_HALF;
+ if (!TEXENV_OPERAND_INVERTED
+ (texUnit->CombineOperandA[1])) {
+ Bmode_A = GR_FUNC_MODE_X;
+ } else {
+ Bmode_A = GR_FUNC_MODE_ONE_MINUS_X;
+ }
+ } else {
+ /*
+ * A is inverted, so try to subtract 1/2
+ * from B.
+ */
+ Amode_A = GR_FUNC_MODE_ONE_MINUS_X;
+ if (!TEXENV_OPERAND_INVERTED
+ (texUnit->CombineOperandA[1])) {
+ Bmode_A = GR_FUNC_MODE_X_MINUS_HALF;
+ } else {
+ /*
+ * Both are inverted. This is the case
+ * we cannot handle properly. We just
+ * choose to not add the - 1/2.
+ */
+ Bmode_A = GR_FUNC_MODE_ONE_MINUS_X;
+ return GL_FALSE;
+ }
+ }
+ C_A = D_A = GR_CMBX_ZERO;
+ Cinv_A = FXTRUE;
+ Dinv_A = Ginv_A = FXFALSE;
+ break;
+ case GL_INTERPOLATE_EXT:
+ /*
+ * The formula is: Arg0 * Arg2 + Arg1 * (1 - Arg2).
+ * We compute this by the formula:
+ * (Arg0 - Arg1) * Arg2 + Arg1
+ * == Arg0 * Arg2 - Arg1 * Arg2 + Arg1
+ * == Arg0 * Arg2 + Arg1 * (1 - Arg2)
+ * However, if both Arg1 is ONE_MINUS_X, the HW does
+ * not support it properly.
+ */
+ TEXENV_SETUP_ARG_A(A_A,
+ texUnit->CombineSourceA[0],
+ texUnit->CombineOperandA[0],
+ incomingAlpha);
+ TEXENV_SETUP_MODE_A(Amode_A,
+ texUnit->CombineOperandA[0]);
+ TEXENV_SETUP_ARG_A(B_A,
+ texUnit->CombineSourceA[1],
+ texUnit->CombineOperandA[1],
+ incomingAlpha);
+ if (!TEXENV_OPERAND_INVERTED(texUnit->CombineOperandA[1])) {
+ Bmode_A = GR_FUNC_MODE_NEGATIVE_X;
+ }
+ else {
+ /*
+ * This case is wrong.
+ */
+ Bmode_A = GR_FUNC_MODE_NEGATIVE_X;
+ return GL_FALSE;
+ }
+ /*
+ * The Source/Operand for the C value must
+ * specify some kind of alpha value.
+ */
+ TEXENV_SETUP_ARG_A(C_A,
+ texUnit->CombineSourceA[2],
+ texUnit->CombineOperandA[2],
+ incomingAlpha);
+ Cinv_A = FXFALSE;
+ D_A = GR_CMBX_B;
+ Dinv_A = Ginv_A = FXFALSE;
+ break;
+ default:
+ /*
+ * This is here mostly to keep from getting
+ * a compiler warning about these not being set.
+ * However, this should set all the alpha values
+ * to one.
+ */
+ A_A = B_A = C_A = D_A = GR_CMBX_ZERO;
+ Amode_A = Bmode_A = GR_FUNC_MODE_X;
+ Cinv_A = Dinv_A = FXFALSE;
+ Ginv_A = FXTRUE;
+ break;
+ }
+ /*
+ * Save the parameters.
+ */
+ env->Color.SourceA = A_RGB;
+ env->Color.ModeA = Amode_RGB;
+ env->Color.SourceB = B_RGB;
+ env->Color.ModeB = Bmode_RGB;
+ env->Color.SourceC = C_RGB;
+ env->Color.InvertC = Cinv_RGB;
+ env->Color.SourceD = D_RGB;
+ env->Color.InvertD = Dinv_RGB;
+ env->Color.Shift = Shift_RGB;
+ env->Color.Invert = Ginv_RGB;
+ env->Alpha.SourceA = A_A;
+ env->Alpha.ModeA = Amode_A;
+ env->Alpha.SourceB = B_A;
+ env->Alpha.ModeB = Bmode_A;
+ env->Alpha.SourceC = C_A;
+ env->Alpha.InvertC = Cinv_A;
+ env->Alpha.SourceD = D_A;
+ env->Alpha.InvertD = Dinv_A;
+ env->Alpha.Shift = Shift_A;
+ env->Alpha.Invert = Ginv_A;
+ env->EnvColor = PACK_RGBA32(texUnit->EnvColor[0] * 255.0F,
+ texUnit->EnvColor[1] * 255.0F,
+ texUnit->EnvColor[2] * 255.0F,
+ texUnit->EnvColor[3] * 255.0F);
+ }
+ break;
+
+ default:
+ _mesa_problem(ctx, "%s: Bad envMode", __FUNCTION__);
+ }
+
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_ENV;
+
+ fxMesa->ColorCombineExt.SourceA = GR_CMBX_TEXTURE_RGB;
+ fxMesa->ColorCombineExt.ModeA = GR_FUNC_MODE_X,
+ fxMesa->ColorCombineExt.SourceB = GR_CMBX_ZERO;
+ fxMesa->ColorCombineExt.ModeB = GR_FUNC_MODE_X;
+ fxMesa->ColorCombineExt.SourceC = GR_CMBX_ZERO;
+ fxMesa->ColorCombineExt.InvertC = FXTRUE;
+ fxMesa->ColorCombineExt.SourceD = GR_CMBX_ZERO;
+ fxMesa->ColorCombineExt.InvertD = FXFALSE;
+ fxMesa->ColorCombineExt.Shift = 0;
+ fxMesa->ColorCombineExt.Invert = FXFALSE;
+ fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+ fxMesa->AlphaCombineExt.SourceA = GR_CMBX_TEXTURE_ALPHA;
+ fxMesa->AlphaCombineExt.ModeA = GR_FUNC_MODE_X;
+ fxMesa->AlphaCombineExt.SourceB = GR_CMBX_ZERO;
+ fxMesa->AlphaCombineExt.ModeB = GR_FUNC_MODE_X;
+ fxMesa->AlphaCombineExt.SourceC = GR_CMBX_ZERO;
+ fxMesa->AlphaCombineExt.InvertC = FXTRUE;
+ fxMesa->AlphaCombineExt.SourceD = GR_CMBX_ZERO;
+ fxMesa->AlphaCombineExt.InvertD = FXFALSE;
+ fxMesa->AlphaCombineExt.Shift = 0;
+ fxMesa->AlphaCombineExt.Invert = FXFALSE;
+ fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+ return GL_TRUE; /* success */
+}
+
+
+
+/*
+ * Setup the Voodoo3 texture environment for a single texture unit.
+ * Return GL_TRUE for success, GL_FALSE for failure.
+ * If failure, we'll use software rendering.
+ */
+static GLboolean
+SetupSingleTexEnvVoodoo3(GLcontext *ctx, int unit,
+ GLenum envMode, GLenum baseFormat)
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+ GrCombineLocal_t localc, locala;
+ struct tdfx_combine alphaComb, colorComb;
+
+ if (1 /*iteratedRGBA*/)
+ localc = locala = GR_COMBINE_LOCAL_ITERATED;
+ else
+ localc = locala = GR_COMBINE_LOCAL_CONSTANT;
+
+ switch (envMode) {
+ case GL_DECAL:
+ alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_NONE;
+ alphaComb.Invert = FXFALSE;
+ colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
+ colorComb.Factor = GR_COMBINE_FACTOR_TEXTURE_ALPHA;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ colorComb.Invert = FXFALSE;
+ break;
+ case GL_MODULATE:
+ alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ alphaComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ alphaComb.Invert = FXFALSE;
+ if (baseFormat == GL_ALPHA) {
+ colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_NONE;
+ colorComb.Invert = FXFALSE;
+ }
+ else {
+ colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ colorComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ colorComb.Invert = FXFALSE;
+ }
+ break;
+
+ case GL_BLEND:
+ /*
+ * XXX we can't do real GL_BLEND mode. These settings assume that
+ * the TexEnv color is black and incoming fragment color is white.
+ */
+ if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+ /* Av = Af */
+ alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_NONE;
+ alphaComb.Invert = FXFALSE;
+ }
+ else if (baseFormat == GL_INTENSITY) {
+ /* Av = Af * (1 - It) + Ac * It */
+ /* XXX this is wrong */
+ alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_NONE;
+ alphaComb.Invert = FXFALSE;
+ }
+ else {
+ /* Av = Af * At */
+ alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ alphaComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ alphaComb.Invert = FXFALSE;
+ }
+ if (baseFormat == GL_ALPHA) {
+ colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_NONE;
+ colorComb.Invert = FXFALSE;
+ }
+ else {
+ colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ colorComb.Factor = GR_COMBINE_FACTOR_ONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ colorComb.Invert = FXTRUE;
+ }
+ /* XXX return GL_FALSE for modes we don't support */
+ break;
+
+ case GL_REPLACE:
+ if ((baseFormat == GL_RGB) || (baseFormat == GL_LUMINANCE)) {
+ alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_NONE;
+ alphaComb.Invert = FXFALSE;
+ }
+ else {
+ alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ alphaComb.Factor = GR_COMBINE_FACTOR_ONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ alphaComb.Invert = FXFALSE;
+ }
+ if (baseFormat == GL_ALPHA) {
+ colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_NONE;
+ colorComb.Invert = FXFALSE;
+ }
+ else {
+ colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ colorComb.Factor = GR_COMBINE_FACTOR_ONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ colorComb.Invert = FXFALSE;
+ }
+ break;
+
+ case GL_ADD:
+ if (baseFormat == GL_ALPHA ||
+ baseFormat == GL_LUMINANCE_ALPHA ||
+ baseFormat == GL_RGBA) {
+ /* product of texel and fragment alpha */
+ alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ alphaComb.Factor = GR_COMBINE_FACTOR_LOCAL;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ alphaComb.Invert = FXFALSE;
+ }
+ else if (baseFormat == GL_LUMINANCE || baseFormat == GL_RGB) {
+ /* fragment alpha is unchanged */
+ alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ alphaComb.Factor = GR_COMBINE_FACTOR_NONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_NONE;
+ alphaComb.Invert = FXFALSE;
+ }
+ else {
+ ASSERT(baseFormat == GL_INTENSITY);
+ /* sum of texel and fragment alpha */
+ alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
+ alphaComb.Factor = GR_COMBINE_FACTOR_ONE;
+ alphaComb.Local = locala;
+ alphaComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ alphaComb.Invert = FXFALSE;
+ }
+ if (baseFormat == GL_ALPHA) {
+ /* rgb unchanged */
+ colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+ colorComb.Factor = GR_COMBINE_FACTOR_NONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_NONE;
+ colorComb.Invert = FXFALSE;
+ }
+ else {
+ /* sum of texel and fragment rgb */
+ colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
+ colorComb.Factor = GR_COMBINE_FACTOR_ONE;
+ colorComb.Local = localc;
+ colorComb.Other = GR_COMBINE_OTHER_TEXTURE;
+ colorComb.Invert = FXFALSE;
+ }
+ break;
+
+ default:
+ _mesa_problem(ctx, "bad texture env mode in %s", __FUNCTION__);
+ }
+
+ if (colorComb.Function != fxMesa->ColorCombine.Function ||
+ colorComb.Factor != fxMesa->ColorCombine.Factor ||
+ colorComb.Local != fxMesa->ColorCombine.Local ||
+ colorComb.Other != fxMesa->ColorCombine.Other ||
+ colorComb.Invert != fxMesa->ColorCombine.Invert) {
+ fxMesa->ColorCombine = colorComb;
+ fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+ }
+
+ if (alphaComb.Function != fxMesa->AlphaCombine.Function ||
+ alphaComb.Factor != fxMesa->AlphaCombine.Factor ||
+ alphaComb.Local != fxMesa->AlphaCombine.Local ||
+ alphaComb.Other != fxMesa->AlphaCombine.Other ||
+ alphaComb.Invert != fxMesa->AlphaCombine.Invert) {
+ fxMesa->AlphaCombine = alphaComb;
+ fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+ }
+ return GL_TRUE;
+}
+
+
+/*
+ * Setup the Voodoo3 texture environment for dual texture units.
+ * Return GL_TRUE for success, GL_FALSE for failure.
+ * If failure, we'll use software rendering.
+ */
+static GLboolean
+SetupDoubleTexEnvVoodoo3(GLcontext *ctx, int tmu0,
+ GLenum envMode0, GLenum baseFormat0,
+ GLenum envMode1, GLenum baseFormat1)
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+ const GrCombineLocal_t locala = GR_COMBINE_LOCAL_ITERATED;
+ const GrCombineLocal_t localc = GR_COMBINE_LOCAL_ITERATED;
+ const int tmu1 = 1 - tmu0;
+
+ if (envMode0 == GL_MODULATE && envMode1 == GL_MODULATE) {
+ GLboolean isalpha[TDFX_NUM_TMU];
+
+ if (baseFormat0 == GL_ALPHA)
+ isalpha[tmu0] = GL_TRUE;
+ else
+ isalpha[tmu0] = GL_FALSE;
+
+ if (baseFormat1 == GL_ALPHA)
+ isalpha[tmu1] = GL_TRUE;
+ else
+ isalpha[tmu1] = GL_FALSE;
+
+ if (isalpha[TDFX_TMU1]) {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_ZERO;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXTRUE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ }
+ else {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ }
+ if (isalpha[TDFX_TMU0]) {
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ else {
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->ColorCombine.Local = localc;
+ fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+ fxMesa->ColorCombine.Invert = FXFALSE;
+ fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->AlphaCombine.Local = locala;
+ fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+ fxMesa->AlphaCombine.Invert = FXFALSE;
+ }
+ else if (envMode0 == GL_REPLACE && envMode1 == GL_BLEND) { /* Quake */
+ if (tmu1 == TDFX_TMU1) {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXTRUE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ else {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE_MINUS_LOCAL;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE_MINUS_LOCAL;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_ONE;
+ fxMesa->ColorCombine.Local = localc;
+ fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+ fxMesa->ColorCombine.Invert = FXFALSE;
+ fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_NONE;
+ fxMesa->AlphaCombine.Local = locala;
+ fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+ fxMesa->AlphaCombine.Invert = FXFALSE;
+ }
+ else if (envMode0 == GL_REPLACE && envMode1 == GL_MODULATE) {
+ /* Quake 2/3 */
+ if (tmu1 == TDFX_TMU1) {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXTRUE;
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ else {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND_OTHER;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+
+ fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_ONE;
+ fxMesa->ColorCombine.Local = localc;
+ fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+ fxMesa->ColorCombine.Invert = FXFALSE;
+ if (baseFormat0 == GL_RGB) {
+ fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_NONE;
+ fxMesa->AlphaCombine.Local = locala;
+ fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+ fxMesa->AlphaCombine.Invert = FXFALSE;
+ }
+ else {
+ fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_ONE;
+ fxMesa->AlphaCombine.Local = locala;
+ fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+ fxMesa->AlphaCombine.Invert = FXFALSE;
+ }
+ }
+ else if (envMode0 == GL_MODULATE && envMode1 == GL_ADD) {
+ /* Quake 3 sky */
+ GLboolean isalpha[TDFX_NUM_TMU];
+ if (baseFormat0 == GL_ALPHA)
+ isalpha[tmu0] = GL_TRUE;
+ else
+ isalpha[tmu0] = GL_FALSE;
+ if (baseFormat1 == GL_ALPHA)
+ isalpha[tmu1] = GL_TRUE;
+ else
+ isalpha[tmu1] = GL_FALSE;
+
+ if (isalpha[TDFX_TMU1]) {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_ZERO;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXTRUE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ }
+ else {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ }
+ if (isalpha[TDFX_TMU0]) {
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ else {
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ }
+ fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->ColorCombine.Local = localc;
+ fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+ fxMesa->ColorCombine.Invert = FXFALSE;
+ fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+ fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_LOCAL;
+ fxMesa->AlphaCombine.Local = locala;
+ fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_TEXTURE;
+ fxMesa->AlphaCombine.Invert = FXFALSE;
+ }
+ else {
+ /*_mesa_problem(ctx, "%s: Unexpected dual texture mode encountered", __FUNCTION__);*/
+ return GL_FALSE;
+ }
+
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_ENV;
+ fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+ fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+ return GL_TRUE;
+}
+
+
+/*
+ * This function makes sure that the correct mipmap levels are loaded
+ * in the right places in memory and then makes the Glide calls to
+ * setup the texture source pointers.
+ */
+static void
+setupSingleTMU(tdfxContextPtr fxMesa, struct gl_texture_object *tObj)
+{
+ struct tdfxSharedState *shared = (struct tdfxSharedState *) fxMesa->glCtx->Shared->DriverData;
+ tdfxTexInfo *ti = TDFX_TEXTURE_DATA(tObj);
+ const GLcontext *ctx = fxMesa->glCtx;
+
+ /* Make sure we're not loaded incorrectly */
+ if (ti->isInTM && !shared->umaTexMemory) {
+ /* if doing filtering between mipmap levels, alternate mipmap levels
+ * must be in alternate TMUs.
+ */
+ if (ti->LODblend) {
+ if (ti->whichTMU != TDFX_TMU_SPLIT)
+ tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
+ }
+ else {
+ if (ti->whichTMU == TDFX_TMU_SPLIT)
+ tdfxTMMoveOutTM_NoLock(fxMesa, tObj);
+ }
+ }
+
+ /* Make sure we're loaded correctly */
+ if (!ti->isInTM) {
+ /* Have to download the texture */
+ if (shared->umaTexMemory) {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU0);
+ }
+ else {
+ /* Voodoo3 (split texture memory) */
+ if (ti->LODblend) {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU_SPLIT);
+ }
+ else {
+#if 0
+ /* XXX putting textures into the second memory bank when the
+ * first bank is full is not working at this time.
+ */
+ if (fxMesa->haveTwoTMUs) {
+ GLint memReq = fxMesa->Glide.grTexTextureMemRequired(
+ GR_MIPMAPLEVELMASK_BOTH, &(ti->info));
+ if (shared->freeTexMem[TDFX_TMU0] > memReq) {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU0);
+ }
+ else {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU1);
+ }
+ }
+ else
+#endif
+ {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj, TDFX_TMU0);
+ }
+ }
+ }
+ }
+
+ if (ti->LODblend && ti->whichTMU == TDFX_TMU_SPLIT) {
+ /* mipmap levels split between texture banks */
+ GLint u;
+
+ if (ti->info.format == GR_TEXFMT_P_8 && !ctx->Texture.SharedPalette) {
+ fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+ fxMesa->TexPalette.Data = &(ti->palette);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+ }
+
+ for (u = 0; u < 2; u++) {
+ fxMesa->TexParams[u].sClamp = ti->sClamp;
+ fxMesa->TexParams[u].tClamp = ti->tClamp;
+ fxMesa->TexParams[u].minFilt = ti->minFilt;
+ fxMesa->TexParams[u].magFilt = ti->magFilt;
+ fxMesa->TexParams[u].mmMode = ti->mmMode;
+ fxMesa->TexParams[u].LODblend = ti->LODblend;
+ fxMesa->TexParams[u].LodBias = ctx->Texture.Unit[u].LodBias;
+ }
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+
+ fxMesa->TexSource[0].StartAddress = ti->tm[TDFX_TMU0]->startAddr;
+ fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_ODD;
+ fxMesa->TexSource[0].Info = &(ti->info);
+ fxMesa->TexSource[1].StartAddress = ti->tm[TDFX_TMU1]->startAddr;
+ fxMesa->TexSource[1].EvenOdd = GR_MIPMAPLEVELMASK_EVEN;
+ fxMesa->TexSource[1].Info = &(ti->info);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+ }
+ else {
+ FxU32 tmu;
+
+ if (ti->whichTMU == TDFX_TMU_BOTH)
+ tmu = TDFX_TMU0;
+ else
+ tmu = ti->whichTMU;
+
+ if (shared->umaTexMemory) {
+ assert(ti->whichTMU == TDFX_TMU0);
+ assert(tmu == TDFX_TMU0);
+ }
+
+ if (ti->info.format == GR_TEXFMT_P_8 && !ctx->Texture.SharedPalette) {
+ fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+ fxMesa->TexPalette.Data = &(ti->palette);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+ }
+
+ /* KW: The alternative is to do the download to the other tmu. If
+ * we get to this point, I think it means we are thrashing the
+ * texture memory, so perhaps it's not a good idea.
+ */
+
+ if (fxMesa->TexParams[tmu].sClamp != ti->sClamp ||
+ fxMesa->TexParams[tmu].tClamp != ti->tClamp ||
+ fxMesa->TexParams[tmu].minFilt != ti->minFilt ||
+ fxMesa->TexParams[tmu].magFilt != ti->magFilt ||
+ fxMesa->TexParams[tmu].mmMode != ti->mmMode ||
+ fxMesa->TexParams[tmu].LODblend != FXFALSE ||
+ fxMesa->TexParams[tmu].LodBias != ctx->Texture.Unit[tmu].LodBias) {
+ fxMesa->TexParams[tmu].sClamp = ti->sClamp;
+ fxMesa->TexParams[tmu].tClamp = ti->tClamp;
+ fxMesa->TexParams[tmu].minFilt = ti->minFilt;
+ fxMesa->TexParams[tmu].magFilt = ti->magFilt;
+ fxMesa->TexParams[tmu].mmMode = ti->mmMode;
+ fxMesa->TexParams[tmu].LODblend = FXFALSE;
+ fxMesa->TexParams[tmu].LodBias = ctx->Texture.Unit[tmu].LodBias;
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+ }
+
+ /* Glide texture source info */
+ fxMesa->TexSource[0].Info = NULL;
+ fxMesa->TexSource[1].Info = NULL;
+ if (ti->tm[tmu]) {
+ fxMesa->TexSource[tmu].StartAddress = ti->tm[tmu]->startAddr;
+ fxMesa->TexSource[tmu].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu].Info = &(ti->info);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+ }
+ }
+
+ fxMesa->sScale0 = ti->sScale;
+ fxMesa->tScale0 = ti->tScale;
+}
+
+static void
+selectSingleTMUSrc(tdfxContextPtr fxMesa, GLint tmu, FxBool LODblend)
+{
+ if (LODblend) {
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE_MINUS_LOD_FRACTION;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+
+ if (fxMesa->haveTwoTMUs) {
+ const struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+ const struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+ int tmu;
+
+ if (shared->umaTexMemory)
+ tmu = GR_TMU0;
+ else
+ tmu = GR_TMU1;
+
+ fxMesa->TexCombine[tmu].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[tmu].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[tmu].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[tmu].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[tmu].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[tmu].InvertAlpha = FXFALSE;
+ }
+ fxMesa->tmuSrc = TDFX_TMU_SPLIT;
+ }
+ else {
+ if (tmu != TDFX_TMU1) {
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ if (fxMesa->haveTwoTMUs) {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_ZERO;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ }
+ fxMesa->tmuSrc = TDFX_TMU0;
+ }
+ else {
+ fxMesa->TexCombine[1].FunctionRGB = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorRGB = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->TexCombine[1].FactorAlpha = GR_COMBINE_FACTOR_NONE;
+ fxMesa->TexCombine[1].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[1].InvertAlpha = FXFALSE;
+ /* GR_COMBINE_FUNCTION_SCALE_OTHER doesn't work ?!? */
+ fxMesa->TexCombine[0].FunctionRGB = GR_COMBINE_FUNCTION_BLEND;
+ fxMesa->TexCombine[0].FactorRGB = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
+ fxMesa->TexCombine[0].FactorAlpha = GR_COMBINE_FACTOR_ONE;
+ fxMesa->TexCombine[0].InvertRGB = FXFALSE;
+ fxMesa->TexCombine[0].InvertAlpha = FXFALSE;
+ fxMesa->tmuSrc = TDFX_TMU1;
+ }
+ }
+
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_ENV;
+}
+
+static void print_state(tdfxContextPtr fxMesa)
+{
+ GLcontext *ctx = fxMesa->glCtx;
+ struct gl_texture_object *tObj0 = ctx->Texture.Unit[0].Current2D;
+ struct gl_texture_object *tObj1 = ctx->Texture.Unit[1].Current2D;
+ GLenum base0 = tObj0->Image[tObj0->BaseLevel] ? tObj0->Image[tObj0->BaseLevel]->Format : 99;
+ GLenum base1 = tObj1->Image[tObj1->BaseLevel] ? tObj1->Image[tObj1->BaseLevel]->Format : 99;
+
+ printf("Unit 0: Enabled: GL=%d Gr=%d\n", ctx->Texture.Unit[0]._ReallyEnabled,
+ fxMesa->TexState.Enabled[0]);
+ printf(" EnvMode: GL=0x%x Gr=0x%x\n", ctx->Texture.Unit[0].EnvMode,
+ fxMesa->TexState.EnvMode[0]);
+ printf(" BaseFmt: GL=0x%x Gr=0x%x\n", base0, fxMesa->TexState.TexFormat[0]);
+
+
+ printf("Unit 1: Enabled: GL=%d Gr=%d\n", ctx->Texture.Unit[1]._ReallyEnabled,
+ fxMesa->TexState.Enabled[1]);
+ printf(" EnvMode: GL=0x%x Gr:0x%x\n", ctx->Texture.Unit[1].EnvMode,
+ fxMesa->TexState.EnvMode[1]);
+ printf(" BaseFmt: GL=0x%x Gr:0x%x\n", base1, fxMesa->TexState.TexFormat[1]);
+}
+
+
+/*
+ * When we're only using a single texture unit, we always use the 0th
+ * Glide/hardware unit, regardless if it's GL_TEXTURE0_ARB or GL_TEXTURE1_ARB
+ * that's enalbed.
+ * Input: ctx - the context
+ * unit - the OpenGL texture unit to use.
+ */
+static void setupTextureSingleTMU(GLcontext * ctx, GLuint unit)
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+ tdfxTexInfo *ti;
+ struct gl_texture_object *tObj;
+ int tmu;
+ GLenum envMode, baseFormat;
+
+ tObj = ctx->Texture.Unit[unit].Current2D;
+ if (tObj->Image[tObj->BaseLevel]->Border > 0) {
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_BORDER, GL_TRUE);
+ return;
+ }
+
+ setupSingleTMU(fxMesa, tObj);
+
+ ti = TDFX_TEXTURE_DATA(tObj);
+ if (ti->whichTMU == TDFX_TMU_BOTH)
+ tmu = TDFX_TMU0;
+ else
+ tmu = ti->whichTMU;
+
+ if (fxMesa->tmuSrc != tmu) {
+ selectSingleTMUSrc(fxMesa, tmu, ti->LODblend);
+ }
+
+ if (ti->reloadImages)
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_IMAGES;
+
+ /* Check if we really need to update the texenv state */
+ envMode = ctx->Texture.Unit[unit].EnvMode;
+ baseFormat = tObj->Image[tObj->BaseLevel]->Format;
+
+ if (TDFX_IS_NAPALM(fxMesa)) {
+ /* see if we really need to update the unit */
+ if (fxMesa->TexState.Enabled[unit] != ctx->Texture.Unit[unit]._ReallyEnabled ||
+ envMode != fxMesa->TexState.EnvMode[0] ||
+ envMode == GL_COMBINE_EXT ||
+ baseFormat != fxMesa->TexState.TexFormat[0]) {
+ struct tdfx_texcombine_ext *otherEnv;
+ if (!SetupTexEnvNapalm(ctx, GL_TRUE,
+ &ctx->Texture.Unit[unit], baseFormat,
+ &fxMesa->TexCombineExt[0])) {
+ /* software fallback */
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+ }
+ /* disable other unit */
+ otherEnv = &fxMesa->TexCombineExt[1];
+ otherEnv->Color.SourceA = GR_CMBX_ZERO;
+ otherEnv->Color.ModeA = GR_FUNC_MODE_ZERO;
+ otherEnv->Color.SourceB = GR_CMBX_ZERO;
+ otherEnv->Color.ModeB = GR_FUNC_MODE_ZERO;
+ otherEnv->Color.SourceC = GR_CMBX_ZERO;
+ otherEnv->Color.InvertC = FXFALSE;
+ otherEnv->Color.SourceD = GR_CMBX_ZERO;
+ otherEnv->Color.InvertD = FXFALSE;
+ otherEnv->Color.Shift = 0;
+ otherEnv->Color.Invert = FXFALSE;
+ otherEnv->Alpha.SourceA = GR_CMBX_ITALPHA;
+ otherEnv->Alpha.ModeA = GR_FUNC_MODE_ZERO;
+ otherEnv->Alpha.SourceB = GR_CMBX_ITALPHA;
+ otherEnv->Alpha.ModeB = GR_FUNC_MODE_ZERO;
+ otherEnv->Alpha.SourceC = GR_CMBX_ZERO;
+ otherEnv->Alpha.InvertC = FXFALSE;
+ otherEnv->Alpha.SourceD = GR_CMBX_ZERO;
+ otherEnv->Alpha.InvertD = FXFALSE;
+ otherEnv->Alpha.Shift = 0;
+ otherEnv->Alpha.Invert = FXFALSE;
+
+ fxMesa->TexState.Enabled[unit] = ctx->Texture.Unit[unit]._ReallyEnabled;
+ fxMesa->TexState.EnvMode[0] = envMode;
+ fxMesa->TexState.TexFormat[0] = baseFormat;
+ fxMesa->TexState.EnvMode[1] = 0;
+ fxMesa->TexState.TexFormat[1] = 0;
+ }
+ }
+ else {
+ /* Voodoo3 */
+
+ /* see if we really need to update the unit */
+ if (fxMesa->TexState.Enabled[unit] != ctx->Texture.Unit[unit]._ReallyEnabled ||
+ envMode != fxMesa->TexState.EnvMode[0] ||
+ envMode == GL_COMBINE_EXT ||
+ baseFormat != fxMesa->TexState.TexFormat[0]) {
+ if (!SetupSingleTexEnvVoodoo3(ctx, tmu, envMode, baseFormat)) {
+ /* software fallback */
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+ }
+ fxMesa->TexState.Enabled[unit] = ctx->Texture.Unit[unit]._ReallyEnabled;
+ fxMesa->TexState.EnvMode[0] = envMode;
+ fxMesa->TexState.TexFormat[0] = baseFormat;
+ fxMesa->TexState.EnvMode[1] = 0;
+ fxMesa->TexState.TexFormat[1] = 0;
+ }
+ }
+}
+
+
+static void
+setupDoubleTMU(tdfxContextPtr fxMesa,
+ struct gl_texture_object *tObj0,
+ struct gl_texture_object *tObj1)
+{
+#define T0_NOT_IN_TMU 0x01
+#define T1_NOT_IN_TMU 0x02
+#define T0_IN_TMU0 0x04
+#define T1_IN_TMU0 0x08
+#define T0_IN_TMU1 0x10
+#define T1_IN_TMU1 0x20
+
+ const struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+ const struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+ const GLcontext *ctx = fxMesa->glCtx;
+ tdfxTexInfo *ti0 = TDFX_TEXTURE_DATA(tObj0);
+ tdfxTexInfo *ti1 = TDFX_TEXTURE_DATA(tObj1);
+ GLuint tstate = 0;
+ int tmu0 = 0, tmu1 = 1;
+
+ if (shared->umaTexMemory) {
+ if (!ti0->isInTM) {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU0);
+ assert(ti0->isInTM);
+ }
+ if (!ti1->isInTM) {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU0);
+ assert(ti1->isInTM);
+ }
+ }
+ else {
+ /* We shouldn't need to do this. There is something wrong with
+ multitexturing when the TMUs are swapped. So, we're forcing
+ them to always be loaded correctly. !!! */
+ if (ti0->whichTMU == TDFX_TMU1)
+ tdfxTMMoveOutTM_NoLock(fxMesa, tObj0);
+ if (ti1->whichTMU == TDFX_TMU0)
+ tdfxTMMoveOutTM_NoLock(fxMesa, tObj1);
+
+ if (ti0->isInTM) {
+ switch (ti0->whichTMU) {
+ case TDFX_TMU0:
+ tstate |= T0_IN_TMU0;
+ break;
+ case TDFX_TMU1:
+ tstate |= T0_IN_TMU1;
+ break;
+ case TDFX_TMU_BOTH:
+ tstate |= T0_IN_TMU0 | T0_IN_TMU1;
+ break;
+ case TDFX_TMU_SPLIT:
+ tstate |= T0_NOT_IN_TMU;
+ break;
+ }
+ }
+ else
+ tstate |= T0_NOT_IN_TMU;
+
+ if (ti1->isInTM) {
+ switch (ti1->whichTMU) {
+ case TDFX_TMU0:
+ tstate |= T1_IN_TMU0;
+ break;
+ case TDFX_TMU1:
+ tstate |= T1_IN_TMU1;
+ break;
+ case TDFX_TMU_BOTH:
+ tstate |= T1_IN_TMU0 | T1_IN_TMU1;
+ break;
+ case TDFX_TMU_SPLIT:
+ tstate |= T1_NOT_IN_TMU;
+ break;
+ }
+ }
+ else
+ tstate |= T1_NOT_IN_TMU;
+
+ /* Move texture maps into TMUs */
+
+ if (!(((tstate & T0_IN_TMU0) && (tstate & T1_IN_TMU1)) ||
+ ((tstate & T0_IN_TMU1) && (tstate & T1_IN_TMU0)))) {
+ if (tObj0 == tObj1) {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU_BOTH);
+ }
+ else {
+ /* Find the minimal way to correct the situation */
+ if ((tstate & T0_IN_TMU0) || (tstate & T1_IN_TMU1)) {
+ /* We have one in the standard order, setup the other */
+ if (tstate & T0_IN_TMU0) {
+ /* T0 is in TMU0, put T1 in TMU1 */
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU1);
+ }
+ else {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU0);
+ }
+ /* tmu0 and tmu1 are setup */
+ }
+ else if ((tstate & T0_IN_TMU1) || (tstate & T1_IN_TMU0)) {
+ /* we have one in the reverse order, setup the other */
+ if (tstate & T1_IN_TMU0) {
+ /* T1 is in TMU0, put T0 in TMU1 */
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU1);
+ }
+ else {
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU0);
+ }
+ tmu0 = 1;
+ tmu1 = 0;
+ }
+ else { /* Nothing is loaded */
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj0, TDFX_TMU0);
+ tdfxTMMoveInTM_NoLock(fxMesa, tObj1, TDFX_TMU1);
+ /* tmu0 and tmu1 are setup */
+ }
+ }
+ }
+ }
+
+ ti0->lastTimeUsed = fxMesa->texBindNumber;
+ ti1->lastTimeUsed = fxMesa->texBindNumber;
+
+
+ if (!ctx->Texture.SharedPalette) {
+ if (ti0->info.format == GR_TEXFMT_P_8) {
+ fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+ fxMesa->TexPalette.Data = &(ti0->palette);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+ }
+ else if (ti1->info.format == GR_TEXFMT_P_8) {
+ fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+ fxMesa->TexPalette.Data = &(ti1->palette);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+ }
+ else {
+ fxMesa->TexPalette.Data = NULL;
+ }
+ }
+
+ /*
+ * Setup Unit 0
+ */
+ assert(ti0->isInTM);
+ assert(ti0->tm[tmu0]);
+ fxMesa->TexSource[tmu0].StartAddress = ti0->tm[tmu0]->startAddr;
+ fxMesa->TexSource[tmu0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu0].Info = &(ti0->info);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+
+ if (fxMesa->TexParams[tmu0].sClamp != ti0->sClamp ||
+ fxMesa->TexParams[tmu0].tClamp != ti0->tClamp ||
+ fxMesa->TexParams[tmu0].minFilt != ti0->minFilt ||
+ fxMesa->TexParams[tmu0].magFilt != ti0->magFilt ||
+ fxMesa->TexParams[tmu0].mmMode != ti0->mmMode ||
+ fxMesa->TexParams[tmu0].LODblend != FXFALSE ||
+ fxMesa->TexParams[tmu0].LodBias != ctx->Texture.Unit[tmu0].LodBias) {
+ fxMesa->TexParams[tmu0].sClamp = ti0->sClamp;
+ fxMesa->TexParams[tmu0].tClamp = ti0->tClamp;
+ fxMesa->TexParams[tmu0].minFilt = ti0->minFilt;
+ fxMesa->TexParams[tmu0].magFilt = ti0->magFilt;
+ fxMesa->TexParams[tmu0].mmMode = ti0->mmMode;
+ fxMesa->TexParams[tmu0].LODblend = FXFALSE;
+ fxMesa->TexParams[tmu0].LodBias = ctx->Texture.Unit[tmu0].LodBias;
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+ }
+
+ /*
+ * Setup Unit 1
+ */
+ if (shared->umaTexMemory) {
+ ASSERT(ti1->isInTM);
+ ASSERT(ti1->tm[0]);
+ fxMesa->TexSource[tmu1].StartAddress = ti1->tm[0]->startAddr;
+ fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu1].Info = &(ti1->info);
+ }
+ else {
+ ASSERT(ti1->isInTM);
+ ASSERT(ti1->tm[tmu1]);
+ fxMesa->TexSource[tmu1].StartAddress = ti1->tm[tmu1]->startAddr;
+ fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu1].Info = &(ti1->info);
+ }
+
+ if (fxMesa->TexParams[tmu1].sClamp != ti1->sClamp ||
+ fxMesa->TexParams[tmu1].tClamp != ti1->tClamp ||
+ fxMesa->TexParams[tmu1].minFilt != ti1->minFilt ||
+ fxMesa->TexParams[tmu1].magFilt != ti1->magFilt ||
+ fxMesa->TexParams[tmu1].mmMode != ti1->mmMode ||
+ fxMesa->TexParams[tmu1].LODblend != FXFALSE ||
+ fxMesa->TexParams[tmu1].LodBias != ctx->Texture.Unit[tmu1].LodBias) {
+ fxMesa->TexParams[tmu1].sClamp = ti1->sClamp;
+ fxMesa->TexParams[tmu1].tClamp = ti1->tClamp;
+ fxMesa->TexParams[tmu1].minFilt = ti1->minFilt;
+ fxMesa->TexParams[tmu1].magFilt = ti1->magFilt;
+ fxMesa->TexParams[tmu1].mmMode = ti1->mmMode;
+ fxMesa->TexParams[tmu1].LODblend = FXFALSE;
+ fxMesa->TexParams[tmu1].LodBias = ctx->Texture.Unit[tmu1].LodBias;
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PARAMS;
+ }
+
+ fxMesa->sScale0 = ti0->sScale;
+ fxMesa->tScale0 = ti0->tScale;
+ fxMesa->sScale1 = ti1->sScale;
+ fxMesa->tScale1 = ti1->tScale;
+
+#undef T0_NOT_IN_TMU
+#undef T1_NOT_IN_TMU
+#undef T0_IN_TMU0
+#undef T1_IN_TMU0
+#undef T0_IN_TMU1
+#undef T1_IN_TMU1
+}
+
+static void setupTextureDoubleTMU(GLcontext * ctx)
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+ struct gl_texture_object *tObj0 = ctx->Texture.Unit[0].Current2D;
+ struct gl_texture_object *tObj1 = ctx->Texture.Unit[1].Current2D;
+ tdfxTexInfo *ti0 = TDFX_TEXTURE_DATA(tObj0);
+ tdfxTexInfo *ti1 = TDFX_TEXTURE_DATA(tObj1);
+ struct gl_texture_image *baseImage0 = tObj0->Image[tObj0->BaseLevel];
+ struct gl_texture_image *baseImage1 = tObj1->Image[tObj1->BaseLevel];
+ const GLenum envMode0 = ctx->Texture.Unit[0].EnvMode;
+ const GLenum envMode1 = ctx->Texture.Unit[1].EnvMode;
+
+ if (baseImage0->Border > 0 || baseImage1->Border > 0) {
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_BORDER, GL_TRUE);
+ return;
+ }
+
+ setupDoubleTMU(fxMesa, tObj0, tObj1);
+
+ if (ti0->reloadImages || ti1->reloadImages)
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_IMAGES;
+
+ fxMesa->tmuSrc = TDFX_TMU_BOTH;
+
+ if (TDFX_IS_NAPALM(fxMesa)) {
+ /* Remember, Glide has its texture units numbered in backward
+ * order compared to OpenGL.
+ */
+ GLboolean hw1 = GL_TRUE, hw2 = GL_TRUE;
+
+ /* check if we really need to update glide unit 1 */
+ if (fxMesa->TexState.Enabled[0] != ctx->Texture.Unit[0]._ReallyEnabled ||
+ envMode0 != fxMesa->TexState.EnvMode[1] ||
+ envMode0 == GL_COMBINE_EXT ||
+ baseImage0->Format != fxMesa->TexState.TexFormat[1] ||
+ (fxMesa->Fallback & TDFX_FALLBACK_TEXTURE_ENV)) {
+ hw1 = SetupTexEnvNapalm(ctx, GL_TRUE, &ctx->Texture.Unit[0],
+ baseImage0->Format, &fxMesa->TexCombineExt[1]);
+ fxMesa->TexState.EnvMode[1] = envMode0;
+ fxMesa->TexState.TexFormat[1] = baseImage0->Format;
+ fxMesa->TexState.Enabled[0] = ctx->Texture.Unit[0]._ReallyEnabled;
+ }
+
+ /* check if we really need to update glide unit 0 */
+ if (fxMesa->TexState.Enabled[1] != ctx->Texture.Unit[1]._ReallyEnabled ||
+ envMode1 != fxMesa->TexState.EnvMode[0] ||
+ envMode1 == GL_COMBINE_EXT ||
+ baseImage1->Format != fxMesa->TexState.TexFormat[0] ||
+ (fxMesa->Fallback & TDFX_FALLBACK_TEXTURE_ENV)) {
+ hw2 = SetupTexEnvNapalm(ctx, GL_FALSE, &ctx->Texture.Unit[1],
+ baseImage1->Format, &fxMesa->TexCombineExt[0]);
+ fxMesa->TexState.EnvMode[0] = envMode1;
+ fxMesa->TexState.TexFormat[0] = baseImage1->Format;
+ fxMesa->TexState.Enabled[1] = ctx->Texture.Unit[1]._ReallyEnabled;
+ }
+
+
+ if (!hw1 || !hw2) {
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+ }
+ }
+ else {
+ int unit0, unit1;
+ if ((ti0->whichTMU == TDFX_TMU1) || (ti1->whichTMU == TDFX_TMU0))
+ unit0 = 1;
+ else
+ unit0 = 0;
+ unit1 = 1 - unit0;
+
+ if (fxMesa->TexState.Enabled[0] != ctx->Texture.Unit[0]._ReallyEnabled ||
+ fxMesa->TexState.Enabled[1] != ctx->Texture.Unit[1]._ReallyEnabled ||
+ envMode0 != fxMesa->TexState.EnvMode[unit0] ||
+ envMode0 == GL_COMBINE_EXT ||
+ envMode1 != fxMesa->TexState.EnvMode[unit1] ||
+ envMode1 == GL_COMBINE_EXT ||
+ baseImage0->Format != fxMesa->TexState.TexFormat[unit0] ||
+ baseImage1->Format != fxMesa->TexState.TexFormat[unit1] ||
+ (fxMesa->Fallback & TDFX_FALLBACK_TEXTURE_ENV)) {
+
+ if (!SetupDoubleTexEnvVoodoo3(ctx, unit0,
+ ctx->Texture.Unit[0].EnvMode, baseImage0->Format,
+ ctx->Texture.Unit[1].EnvMode, baseImage1->Format)) {
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+ }
+
+ fxMesa->TexState.EnvMode[unit0] = envMode0;
+ fxMesa->TexState.TexFormat[unit0] = baseImage0->Format;
+ fxMesa->TexState.EnvMode[unit1] = envMode1;
+ fxMesa->TexState.TexFormat[unit1] = baseImage1->Format;
+ fxMesa->TexState.Enabled[0] = ctx->Texture.Unit[0]._ReallyEnabled;
+ fxMesa->TexState.Enabled[1] = ctx->Texture.Unit[1]._ReallyEnabled;
+ }
+ }
+}
+
+
+void
+tdfxUpdateTextureState( GLcontext *ctx )
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_BORDER, GL_FALSE);
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_FALSE);
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+ ctx->Texture.Unit[1]._ReallyEnabled == 0) {
+ LOCK_HARDWARE( fxMesa ); /* XXX remove locking eventually */
+ setupTextureSingleTMU(ctx, 0);
+ UNLOCK_HARDWARE( fxMesa );
+ }
+ else if (ctx->Texture.Unit[0]._ReallyEnabled == 0 &&
+ ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
+ LOCK_HARDWARE( fxMesa );
+ setupTextureSingleTMU(ctx, 1);
+ UNLOCK_HARDWARE( fxMesa );
+ }
+ else if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+ ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
+ LOCK_HARDWARE( fxMesa );
+ setupTextureDoubleTMU(ctx);
+ UNLOCK_HARDWARE( fxMesa );
+ }
+ else {
+ /* disable hardware texturing */
+ if (TDFX_IS_NAPALM(fxMesa)) {
+ fxMesa->ColorCombineExt.SourceA = GR_CMBX_ITRGB;
+ fxMesa->ColorCombineExt.ModeA = GR_FUNC_MODE_X;
+ fxMesa->ColorCombineExt.SourceB = GR_CMBX_ZERO;
+ fxMesa->ColorCombineExt.ModeB = GR_FUNC_MODE_ZERO;
+ fxMesa->ColorCombineExt.SourceC = GR_CMBX_ZERO;
+ fxMesa->ColorCombineExt.InvertC = FXTRUE;
+ fxMesa->ColorCombineExt.SourceD = GR_CMBX_ZERO;
+ fxMesa->ColorCombineExt.InvertD = FXFALSE;
+ fxMesa->ColorCombineExt.Shift = 0;
+ fxMesa->ColorCombineExt.Invert = FXFALSE;
+ fxMesa->AlphaCombineExt.SourceA = GR_CMBX_ITALPHA;
+ fxMesa->AlphaCombineExt.ModeA = GR_FUNC_MODE_X;
+ fxMesa->AlphaCombineExt.SourceB = GR_CMBX_ZERO;
+ fxMesa->AlphaCombineExt.ModeB = GR_FUNC_MODE_ZERO;
+ fxMesa->AlphaCombineExt.SourceC = GR_CMBX_ZERO;
+ fxMesa->AlphaCombineExt.InvertC = FXTRUE;
+ fxMesa->AlphaCombineExt.SourceD = GR_CMBX_ZERO;
+ fxMesa->AlphaCombineExt.InvertD = FXFALSE;
+ fxMesa->AlphaCombineExt.Shift = 0;
+ fxMesa->AlphaCombineExt.Invert = FXFALSE;
+ }
+ else {
+ /* Voodoo 3*/
+ fxMesa->ColorCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->ColorCombine.Factor = GR_COMBINE_FACTOR_NONE;
+ fxMesa->ColorCombine.Local = GR_COMBINE_LOCAL_ITERATED;
+ fxMesa->ColorCombine.Other = GR_COMBINE_OTHER_NONE;
+ fxMesa->ColorCombine.Invert = FXFALSE;
+ fxMesa->AlphaCombine.Function = GR_COMBINE_FUNCTION_LOCAL;
+ fxMesa->AlphaCombine.Factor = GR_COMBINE_FACTOR_NONE;
+ fxMesa->AlphaCombine.Local = GR_COMBINE_LOCAL_ITERATED;
+ fxMesa->AlphaCombine.Other = GR_COMBINE_OTHER_NONE;
+ fxMesa->AlphaCombine.Invert = FXFALSE;
+ }
+
+ fxMesa->TexState.Enabled[0] = 0;
+ fxMesa->TexState.Enabled[1] = 0;
+ fxMesa->TexState.EnvMode[0] = 0;
+ fxMesa->TexState.EnvMode[1] = 0;
+
+ fxMesa->dirty |= TDFX_UPLOAD_COLOR_COMBINE;
+ fxMesa->dirty |= TDFX_UPLOAD_ALPHA_COMBINE;
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled != 0 ||
+ ctx->Texture.Unit[1]._ReallyEnabled != 0) {
+ /* software texture (cube map, rect tex, etc */
+ FALLBACK(fxMesa, TDFX_FALLBACK_TEXTURE_ENV, GL_TRUE);
+ }
+ }
+}
+
+
+
+/*
+ * This is a special case of texture state update.
+ * It's used when we've simply bound a new texture to a texture
+ * unit and the new texture has the exact same attributes as the
+ * previously bound texture.
+ * This is very common in Quake3.
+ */
+void
+tdfxUpdateTextureBinding( GLcontext *ctx )
+{
+ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx);
+ struct gl_texture_object *tObj0 = ctx->Texture.Unit[0].Current2D;
+ struct gl_texture_object *tObj1 = ctx->Texture.Unit[1].Current2D;
+ tdfxTexInfo *ti0 = TDFX_TEXTURE_DATA(tObj0);
+ tdfxTexInfo *ti1 = TDFX_TEXTURE_DATA(tObj1);
+
+ const struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared;
+ const struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData;
+
+ if (ti0) {
+ fxMesa->sScale0 = ti0->sScale;
+ fxMesa->tScale0 = ti0->tScale;
+ if (ti0->info.format == GR_TEXFMT_P_8) {
+ fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+ fxMesa->TexPalette.Data = &(ti0->palette);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+ }
+ else if (ti1 && ti1->info.format == GR_TEXFMT_P_8) {
+ fxMesa->TexPalette.Type = GR_TEXTABLE_PALETTE_6666_EXT;
+ fxMesa->TexPalette.Data = &(ti1->palette);
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_PALETTE;
+ }
+ }
+ if (ti1) {
+ fxMesa->sScale1 = ti1->sScale;
+ fxMesa->tScale1 = ti1->tScale;
+ }
+
+ if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+ ctx->Texture.Unit[0]._ReallyEnabled == 0) {
+ /* Only unit 0 2D enabled */
+ if (shared->umaTexMemory) {
+ fxMesa->TexSource[0].StartAddress = ti0->tm[0]->startAddr;
+ fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[0].Info = &(ti0->info);
+ }
+ else {
+ if (ti0->LODblend && ti0->whichTMU == TDFX_TMU_SPLIT) {
+ fxMesa->TexSource[0].StartAddress = ti0->tm[TDFX_TMU0]->startAddr;
+ fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_ODD;
+ fxMesa->TexSource[0].Info = &(ti0->info);
+ fxMesa->TexSource[1].StartAddress = ti0->tm[TDFX_TMU1]->startAddr;
+ fxMesa->TexSource[1].EvenOdd = GR_MIPMAPLEVELMASK_EVEN;
+ fxMesa->TexSource[1].Info = &(ti0->info);
+ }
+ else {
+ FxU32 tmu;
+ if (ti0->whichTMU == TDFX_TMU_BOTH)
+ tmu = TDFX_TMU0;
+ else
+ tmu = ti0->whichTMU;
+ fxMesa->TexSource[0].Info = NULL;
+ fxMesa->TexSource[1].Info = NULL;
+ if (ti0->tm[tmu]) {
+ fxMesa->TexSource[tmu].StartAddress = ti0->tm[tmu]->startAddr;
+ fxMesa->TexSource[tmu].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu].Info = &(ti0->info);
+ }
+ }
+ }
+ }
+ else if (ctx->Texture.Unit[0]._ReallyEnabled == 0 &&
+ ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) {
+ /* Only unit 1 2D enabled */
+ if (shared->umaTexMemory) {
+ fxMesa->TexSource[0].StartAddress = ti1->tm[0]->startAddr;
+ fxMesa->TexSource[0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[0].Info = &(ti1->info);
+ }
+ }
+ else if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
+ ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) {
+ /* Both 2D enabled */
+ if (shared->umaTexMemory) {
+ const FxU32 tmu0 = 0, tmu1 = 1;
+ fxMesa->TexSource[tmu0].StartAddress = ti0->tm[0]->startAddr;
+ fxMesa->TexSource[tmu0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu0].Info = &(ti0->info);
+
+ fxMesa->TexSource[tmu1].StartAddress = ti1->tm[0]->startAddr;
+ fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu1].Info = &(ti1->info);
+ }
+ else {
+ const FxU32 tmu0 = 0, tmu1 = 1;
+ fxMesa->TexSource[tmu0].StartAddress = ti0->tm[tmu0]->startAddr;
+ fxMesa->TexSource[tmu0].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu0].Info = &(ti0->info);
+
+ fxMesa->TexSource[tmu1].StartAddress = ti1->tm[tmu1]->startAddr;
+ fxMesa->TexSource[tmu1].EvenOdd = GR_MIPMAPLEVELMASK_BOTH;
+ fxMesa->TexSource[tmu1].Info = &(ti1->info);
+ }
+ }
+
+
+ fxMesa->dirty |= TDFX_UPLOAD_TEXTURE_SOURCE;
+}