summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/mga/mga_texstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/mga/mga_texstate.c')
-rw-r--r--src/mesa/drivers/dri/mga/mga_texstate.c747
1 files changed, 747 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/mga/mga_texstate.c b/src/mesa/drivers/dri/mga/mga_texstate.c
new file mode 100644
index 0000000000..fc1406cab9
--- /dev/null
+++ b/src/mesa/drivers/dri/mga/mga_texstate.c
@@ -0,0 +1,747 @@
+/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * (c) Copyright IBM Corporation 2002
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS, IBM AND/OR THEIR SUPPLIERS 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.
+ *
+ * Authors:
+ * Ian Romanick <idr@us.ibm.com>
+ * Keith Whitwell <keithw@tungstengraphics.com>
+ */
+/* $XFree86:$ */
+
+#include "mm.h"
+#include "mgacontext.h"
+#include "mgatex.h"
+#include "mgaregs.h"
+#include "mgatris.h"
+#include "mgaioctl.h"
+
+#include "context.h"
+#include "enums.h"
+#include "macros.h"
+#include "imports.h"
+
+#include "simple_list.h"
+#include "texformat.h"
+
+#define MGA_USE_TABLE_FOR_FORMAT
+#ifdef MGA_USE_TABLE_FOR_FORMAT
+#define TMC_nr_tformat (MESA_FORMAT_YCBCR_REV + 1)
+static const unsigned TMC_tformat[ TMC_nr_tformat ] =
+{
+ [MESA_FORMAT_ARGB8888] = TMC_tformat_tw32 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_RGB565] = TMC_tformat_tw16 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_ARGB4444] = TMC_tformat_tw12 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_ARGB1555] = TMC_tformat_tw15 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_CI8] = TMC_tformat_tw8 | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_YCBCR] = TMC_tformat_tw422uyvy | TMC_takey_1 | TMC_tamask_0,
+ [MESA_FORMAT_YCBCR_REV] = TMC_tformat_tw422 | TMC_takey_1 | TMC_tamask_0,
+};
+#endif
+
+static void
+mgaSetTexImages( mgaContextPtr mmesa,
+ const struct gl_texture_object * tObj )
+{
+ mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
+ struct gl_texture_image *baseImage = tObj->Image[ tObj->BaseLevel ];
+ GLint totalSize;
+ GLint width, height;
+ GLint i;
+ GLint firstLevel, lastLevel, numLevels;
+ GLint log2Width, log2Height;
+ GLuint txformat = 0;
+ GLint ofs;
+
+ /* Set the hardware texture format
+ */
+#ifndef MGA_USE_TABLE_FOR_FORMAT
+ switch (baseImage->TexFormat->MesaFormat) {
+
+ case MESA_FORMAT_ARGB8888: txformat = TMC_tformat_tw32; break;
+ case MESA_FORMAT_RGB565: txformat = TMC_tformat_tw16; break;
+ case MESA_FORMAT_ARGB4444: txformat = TMC_tformat_tw12; break;
+ case MESA_FORMAT_ARGB1555: txformat = TMC_tformat_tw15; break;
+ case MESA_FORMAT_CI8: txformat = TMC_tformat_tw8; break;
+ case MESA_FORMAT_YCBCR: txformat = TMC_tformat_tw422uyvy; break;
+ case MESA_FORMAT_YCBCR_REV: txformat = TMC_tformat_tw422; break;
+
+ default:
+ _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__);
+ return;
+ }
+#else
+ if ( (baseImage->TexFormat->MesaFormat >= TMC_nr_tformat)
+ || (TMC_tformat[ baseImage->TexFormat->MesaFormat ] == 0) )
+ {
+ _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__);
+ return;
+ }
+
+ txformat = TMC_tformat[ baseImage->TexFormat->MesaFormat ];
+
+#endif /* MGA_USE_TABLE_FOR_FORMAT */
+
+ if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) {
+ /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL.
+ */
+
+ firstLevel = lastLevel = tObj->BaseLevel;
+ } else {
+ /* Compute which mipmap levels we really want to send to the hardware.
+ * This depends on the base image size, GL_TEXTURE_MIN_LOD,
+ * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL.
+ * Yes, this looks overly complicated, but it's all needed.
+ */
+
+ firstLevel = tObj->BaseLevel + (GLint)(tObj->MinLod + 0.5);
+ firstLevel = MAX2(firstLevel, tObj->BaseLevel);
+ lastLevel = tObj->BaseLevel + (GLint)(tObj->MaxLod + 0.5);
+ lastLevel = MAX2(lastLevel, tObj->BaseLevel);
+ lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2);
+ lastLevel = MIN2(lastLevel, tObj->MaxLevel);
+ lastLevel = MAX2(firstLevel, lastLevel); /* need at least one level */
+ }
+
+ log2Width = tObj->Image[firstLevel]->WidthLog2;
+ log2Height = tObj->Image[firstLevel]->HeightLog2;
+ width = tObj->Image[firstLevel]->Width;
+ height = tObj->Image[firstLevel]->Height;
+
+ numLevels = MIN2( lastLevel - firstLevel + 1,
+ MGA_IS_G200(mmesa) ? G200_TEX_MAXLEVELS : G400_TEX_MAXLEVELS);
+
+
+ totalSize = 0;
+ for ( i = 0 ; i < numLevels ; i++ ) {
+ const struct gl_texture_image * const texImage = tObj->Image[i+firstLevel];
+
+ if ( (texImage == NULL)
+ || ((i != 0)
+ && ((texImage->Width < 8) || (texImage->Height < 8))) ) {
+ break;
+ }
+
+ t->offsets[i] = totalSize;
+ t->base.dirty_images[0] |= (1<<i);
+
+ totalSize += ((MAX2( texImage->Width, 8 ) *
+ MAX2( texImage->Height, 8 ) *
+ baseImage->TexFormat->TexelBytes) + 31) & ~31;
+ }
+
+ numLevels = i;
+ lastLevel = firstLevel + numLevels - 1;
+
+ /* save these values */
+ t->base.firstLevel = firstLevel;
+ t->base.lastLevel = lastLevel;
+
+ t->base.totalSize = totalSize;
+
+ /* setup hardware register values */
+ t->setup.texctl &= (TMC_tformat_MASK & TMC_tpitch_MASK
+ & TMC_tpitchext_MASK);
+ t->setup.texctl |= txformat;
+
+
+ /* Set the texture width. In order to support non-power of 2 textures and
+ * textures larger than 1024 texels wide, "linear" pitch must be used. For
+ * the linear pitch, if the width is 2048, a value of zero is used.
+ */
+
+ t->setup.texctl |= TMC_tpitchlin_enable;
+ t->setup.texctl |= (width & (2048 - 1)) << TMC_tpitchext_SHIFT;
+
+
+ /* G400 specifies the number of mip levels in a strange way. Since there
+ * are up to 12 levels, it requires 4 bits. Three of the bits are at the
+ * high end of TEXFILTER. The other bit is in the middle. Weird.
+ */
+
+ t->setup.texfilter &= TF_mapnb_MASK & TF_mapnbhigh_MASK & TF_reserved_MASK;
+ t->setup.texfilter |= (((numLevels-1) & 0x07) << (TF_mapnb_SHIFT));
+ t->setup.texfilter |= (((numLevels-1) & 0x08) << (TF_mapnbhigh_SHIFT - 3));
+
+ /* warp texture registers */
+ ofs = MGA_IS_G200(mmesa) ? 28 : 11;
+
+ t->setup.texwidth = (MGA_FIELD(TW_twmask, width - 1) |
+ MGA_FIELD(TW_rfw, (10 - log2Width - 8) & 63 ) |
+ MGA_FIELD(TW_tw, (log2Width + ofs ) | 0x40 ));
+
+ t->setup.texheight = (MGA_FIELD(TH_thmask, height - 1) |
+ MGA_FIELD(TH_rfh, (10 - log2Height - 8) & 63 ) |
+ MGA_FIELD(TH_th, (log2Height + ofs ) | 0x40 ));
+
+ mgaUploadTexImages( mmesa, t );
+}
+
+
+/* ================================================================
+ * Texture unit state management
+ */
+
+static void mgaUpdateTextureEnvG200( GLcontext *ctx, GLuint unit )
+{
+ struct gl_texture_object *tObj = ctx->Texture.Unit[0]._Current;
+ mgaTextureObjectPtr t;
+
+ if (!tObj || !tObj->DriverData)
+ return;
+
+ t = (mgaTextureObjectPtr)tObj->DriverData;
+
+ t->setup.texctl2 &= ~TMC_decalblend_enable;
+
+ switch (ctx->Texture.Unit[0].EnvMode) {
+ case GL_REPLACE:
+ t->setup.texctl &= ~TMC_tmodulate_enable;
+ break;
+ case GL_MODULATE:
+ t->setup.texctl |= TMC_tmodulate_enable;
+ break;
+ case GL_DECAL:
+ t->setup.texctl &= ~TMC_tmodulate_enable;
+ t->setup.texctl2 |= TMC_decalblend_enable;
+ break;
+ case GL_BLEND:
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
+ break;
+ default:
+ break;
+ }
+}
+
+
+#define MGA_DISABLE 0
+#define MGA_REPLACE 1
+#define MGA_MODULATE 2
+#define MGA_DECAL 3
+#define MGA_BLEND 4
+#define MGA_ADD 5
+#define MGA_MAX_COMBFUNC 6
+
+static const GLuint g400_color_combine[][MGA_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2 ),
+
+ /* GL_MODULATE
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2),
+
+ /* GL_BLEND
+ */
+ (0),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+ },
+
+ /* Unit 1:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2 ),
+
+ /* GL_MODULATE
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_alpha_prevstage |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_sel_arg1 |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2 ),
+
+ /* GL_BLEND
+ */
+ (0),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_alpha_prevstage |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+ },
+};
+
+static const GLuint g400_alpha_combine[][MGA_MAX_COMBFUNC] =
+{
+ /* Unit 0:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg2 |
+ TD0_color_arg2_diffuse |
+ TD0_alpha_sel_arg1 ),
+
+ /* GL_MODULATE
+ * FIXME: Is this correct?
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_arg2 |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2),
+
+ /* GL_BLEND
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+ },
+
+ /* Unit 1:
+ */
+ {
+ /* Disable combiner stage
+ */
+ (0),
+
+ /* GL_REPLACE
+ */
+ (TD0_color_sel_arg2 |
+ TD0_color_arg2_diffuse |
+ TD0_alpha_sel_arg1 ),
+
+ /* GL_MODULATE
+ * FIXME: Is this correct?
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_alpha_prevstage |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+
+ /* GL_DECAL
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_sel_arg2 |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2),
+
+ /* GL_BLEND
+ */
+ (TD0_color_arg2_diffuse |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_mul),
+
+ /* GL_ADD
+ */
+ (TD0_color_arg2_prevstage |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_mul),
+ },
+};
+
+static void mgaUpdateTextureEnvG400( GLcontext *ctx, GLuint unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit);
+ GLenum format;
+
+ if ( tObj != ctx->Texture.Unit[source].Current2D || !tObj )
+ return;
+
+ format = tObj->Image[tObj->BaseLevel]->Format;
+
+ switch (ctx->Texture.Unit[source].EnvMode) {
+ case GL_REPLACE:
+ if (format == GL_RGB || format == GL_LUMINANCE) {
+ *reg = g400_color_combine[unit][MGA_REPLACE];
+ }
+ else if (format == GL_ALPHA) {
+ *reg = g400_alpha_combine[unit][MGA_REPLACE];
+ }
+ else {
+ *reg = (TD0_color_sel_arg1 |
+ TD0_alpha_sel_arg1 );
+ }
+ break;
+
+ case GL_MODULATE:
+ *reg = g400_color_combine[unit][MGA_MODULATE];
+ break;
+ case GL_DECAL:
+ if (format == GL_RGB) {
+ *reg = g400_color_combine[unit][MGA_DECAL];
+ }
+ else if ( format == GL_RGBA ) {
+#if 0
+ if (unit == 0) {
+ /* this doesn't work */
+ *reg = (TD0_color_arg2_diffuse |
+ TD0_color_alpha_currtex |
+ TD0_color_alpha2inv_enable |
+ TD0_color_arg2mul_alpha2 |
+ TD0_color_arg1mul_alpha1 |
+ TD0_color_blend_enable |
+ TD0_color_arg1add_mulout |
+ TD0_color_arg2add_mulout |
+ TD0_color_add_add |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg2 );
+ }
+ else {
+ *reg = (TD0_color_arg2_prevstage |
+ TD0_color_alpha_currtex |
+ TD0_color_alpha2inv_enable |
+ TD0_color_arg2mul_alpha2 |
+ TD0_color_arg1mul_alpha1 |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2 );
+ }
+#else
+ /* s/w fallback, pretty sure we can't do in h/w */
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
+ if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
+ fprintf( stderr, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n",
+ unit );
+#endif
+ }
+ else {
+ *reg = g400_alpha_combine[unit][MGA_DECAL];
+ }
+ break;
+
+ case GL_ADD:
+ if (format == GL_INTENSITY) {
+ if (unit == 0) {
+ *reg = ( TD0_color_arg2_diffuse |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_add_enable |
+ TD0_alpha_sel_add);
+ }
+ else {
+ *reg = ( TD0_color_arg2_prevstage |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_add_enable |
+ TD0_alpha_sel_add);
+ }
+ }
+ else if (format == GL_ALPHA) {
+ *reg = g400_alpha_combine[unit][MGA_ADD];
+ }
+ else {
+ *reg = g400_color_combine[unit][MGA_ADD];
+ }
+ break;
+
+ case GL_BLEND:
+ if (format == GL_ALPHA) {
+ *reg = g400_alpha_combine[unit][MGA_BLEND];
+ }
+ else {
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE );
+ if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK )
+ fprintf( stderr, "FALLBACK: GL_BLEND envcolor=0x%08x\n",
+ mmesa->envcolor );
+
+ /* Do singletexture GL_BLEND with 'all ones' env-color
+ * by using both texture units. Multitexture gl_blend
+ * is a fallback.
+ */
+ if (unit == 0) {
+ /* Part 1: R1 = Rf ( 1 - Rt )
+ * A1 = Af At
+ */
+ *reg = ( TD0_color_arg2_diffuse |
+ TD0_color_arg1_inv_enable |
+ TD0_color_sel_mul |
+ TD0_alpha_arg2_diffuse |
+ TD0_alpha_sel_arg1);
+ } else {
+ /* Part 2: R2 = R1 + Rt
+ * A2 = A1
+ */
+ *reg = ( TD0_color_arg2_prevstage |
+ TD0_color_add_add |
+ TD0_color_sel_add |
+ TD0_alpha_arg2_prevstage |
+ TD0_alpha_sel_arg2);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void disable_tex( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+
+ /* Texture unit disabled */
+
+ if ( mmesa->CurrentTexObj[unit] != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ mmesa->CurrentTexObj[unit]->base.bound &= ~(1UL << unit);
+ mmesa->CurrentTexObj[unit] = NULL;
+ }
+
+ if ( unit != 0 ) {
+ mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0;
+ }
+
+ if ( ctx->Texture._EnabledUnits == 0 ) {
+ mmesa->setup.dwgctl &= DC_opcod_MASK;
+ mmesa->setup.dwgctl |= DC_opcod_trap;
+ mmesa->hw.alpha_sel = AC_alphasel_diffused;
+ }
+
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit);
+}
+
+static GLboolean enable_tex_2d( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ const struct gl_texture_object *tObj = texUnit->_Current;
+ mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
+
+ /* Upload teximages (not pipelined)
+ */
+ if (t->base.dirty_images[0]) {
+ FLUSH_BATCH( mmesa );
+ mgaSetTexImages( mmesa, tObj );
+ if ( t->base.memBlock == NULL ) {
+ return GL_FALSE;
+ }
+ }
+
+ return GL_TRUE;
+}
+
+static GLboolean update_tex_common( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT(ctx);
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+ struct gl_texture_object *tObj = texUnit->_Current;
+ mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData;
+
+ /* Fallback if there's a texture border */
+ if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) {
+ return GL_FALSE;
+ }
+
+
+ /* Update state if this is a different texture object to last
+ * time.
+ */
+ if ( mmesa->CurrentTexObj[unit] != t ) {
+ if ( mmesa->CurrentTexObj[unit] != NULL ) {
+ /* The old texture is no longer bound to this texture unit.
+ * Mark it as such.
+ */
+
+ mmesa->CurrentTexObj[unit]->base.bound &= ~(1UL << unit);
+ }
+
+ mmesa->CurrentTexObj[unit] = t;
+ t->base.bound |= (1UL << unit);
+
+ driUpdateTextureLRU( (driTextureObject *) t ); /* done too often */
+ }
+
+ /* register setup */
+ if ( unit == 1 ) {
+ mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0;
+ }
+
+ t->setup.texctl2 &= TMC_dualtex_MASK;
+ if (ctx->Texture._EnabledUnits == 0x03) {
+ t->setup.texctl2 |= TMC_dualtex_enable;
+ }
+
+ /* FIXME: The Radeon has some cached state so that it can avoid calling
+ * FIXME: UpdateTextureEnv in some cases. Is that possible here?
+ */
+ if (MGA_IS_G400(mmesa)) {
+ /* G400: Regardless of texture env mode, we use the alpha from the
+ * texture unit (AC_alphasel_fromtex) since it will have already
+ * been modulated by the incoming fragment color, if needed.
+ * We don't want (AC_alphasel_modulate) since that'll effectively
+ * do the modulation twice.
+ */
+ mmesa->hw.alpha_sel = AC_alphasel_fromtex;
+
+ mgaUpdateTextureEnvG400( ctx, unit );
+ } else {
+ mmesa->hw.alpha_sel = 0;
+ switch (ctx->Texture.Unit[0].EnvMode) {
+ case GL_DECAL:
+ mmesa->hw.alpha_sel |= AC_alphasel_diffused;
+ case GL_REPLACE:
+ mmesa->hw.alpha_sel |= AC_alphasel_fromtex;
+ break;
+ case GL_BLEND:
+ case GL_MODULATE:
+ mmesa->hw.alpha_sel |= AC_alphasel_modulated;
+ break;
+ default:
+ break;
+ }
+
+ mgaUpdateTextureEnvG200( ctx, unit );
+ }
+
+ mmesa->setup.dwgctl &= DC_opcod_MASK;
+ mmesa->setup.dwgctl |= DC_opcod_texture_trap;
+ mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit);
+
+ FALLBACK( ctx, MGA_FALLBACK_BORDER_MODE, t->border_fallback );
+ return !t->border_fallback;
+}
+
+
+static GLboolean updateTextureUnit( GLcontext *ctx, int unit )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ const int source = mmesa->tmu_source[unit];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source];
+
+
+ if ( texUnit->_ReallyEnabled == TEXTURE_2D_BIT) {
+ return(enable_tex_2d( ctx, unit ) &&
+ update_tex_common( ctx, unit ));
+ }
+ else if ( texUnit->_ReallyEnabled ) {
+ return GL_FALSE;
+ }
+ else {
+ disable_tex( ctx, unit );
+ return GL_TRUE;
+ }
+}
+
+/* The G400 is now programmed quite differently wrt texture environment.
+ */
+void mgaUpdateTextureState( GLcontext *ctx )
+{
+ mgaContextPtr mmesa = MGA_CONTEXT( ctx );
+ GLboolean ok;
+ unsigned i;
+
+
+ /* This works around a quirk with the MGA hardware. If only OpenGL
+ * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The
+ * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used.
+ */
+
+ mmesa->tmu_source[0] = 0;
+ mmesa->tmu_source[1] = 1;
+
+ if ((ctx->Texture._EnabledUnits & 0x03) == 0x02) {
+ /* only texture 1 enabled */
+ mmesa->tmu_source[0] = 1;
+ mmesa->tmu_source[1] = 0;
+ }
+
+ for ( i = 0, ok = GL_TRUE
+ ; (i < ctx->Const.MaxTextureUnits) && ok
+ ; i++ ) {
+ ok = updateTextureUnit( ctx, i );
+ }
+
+ FALLBACK( ctx, MGA_FALLBACK_TEXTURE, !ok );
+
+ /* FIXME: I believe that ChooseVertexState should be called here instead of
+ * FIXME: in mgaDDValidateState.
+ */
+}