/* -*- mode: c; c-basic-offset: 3 -*- */ /* * Copyright 2000 Gareth Hughes * 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 * GARETH HUGHES 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: * Gareth Hughes * Leif Delgass * José Fonseca */ #include "main/glheader.h" #include "main/imports.h" #include "main/context.h" #include "main/macros.h" #include "mach64_context.h" #include "mach64_ioctl.h" #include "mach64_tris.h" #include "mach64_tex.h" static void mach64SetTexImages( mach64ContextPtr mmesa, const struct gl_texture_object *tObj ) { mach64TexObjPtr t = (mach64TexObjPtr) tObj->DriverData; struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; int totalSize; assert(t); assert(baseImage); if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) fprintf( stderr, "%s( %p )\n", __FUNCTION__, tObj ); switch (baseImage->TexFormat) { case MESA_FORMAT_ARGB8888: t->textureFormat = MACH64_DATATYPE_ARGB8888; break; case MESA_FORMAT_ARGB4444: t->textureFormat = MACH64_DATATYPE_ARGB4444; break; case MESA_FORMAT_RGB565: t->textureFormat = MACH64_DATATYPE_RGB565; break; case MESA_FORMAT_ARGB1555: t->textureFormat = MACH64_DATATYPE_ARGB1555; break; case MESA_FORMAT_RGB332: t->textureFormat = MACH64_DATATYPE_RGB332; break; case MESA_FORMAT_RGB888: t->textureFormat = MACH64_DATATYPE_RGB8; break; case MESA_FORMAT_CI8: t->textureFormat = MACH64_DATATYPE_CI8; break; case MESA_FORMAT_YCBCR: t->textureFormat = MACH64_DATATYPE_YVYU422; break; case MESA_FORMAT_YCBCR_REV: t->textureFormat = MACH64_DATATYPE_VYUY422; break; default: _mesa_problem(mmesa->glCtx, "Bad texture format in %s", __FUNCTION__); }; totalSize = ( baseImage->Height * baseImage->Width * _mesa_get_format_bytes(baseImage->TexFormat) ); totalSize = (totalSize + 31) & ~31; t->base.totalSize = totalSize; t->base.firstLevel = tObj->BaseLevel; t->base.lastLevel = tObj->BaseLevel; /* Set the texture format */ if ( ( baseImage->_BaseFormat == GL_RGBA ) || ( baseImage->_BaseFormat == GL_ALPHA ) || ( baseImage->_BaseFormat == GL_LUMINANCE_ALPHA ) ) { t->hasAlpha = 1; } else { t->hasAlpha = 0; } t->widthLog2 = baseImage->WidthLog2; t->heightLog2 = baseImage->HeightLog2; t->maxLog2 = baseImage->MaxLog2; } static void mach64UpdateTextureEnv( struct gl_context *ctx, int unit ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); GLint source = mmesa->tmu_source[unit]; const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; const struct gl_texture_object *tObj = texUnit->_Current; const GLenum format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat; GLuint s = mmesa->setup.scale_3d_cntl; if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %p, %d )\n", __FUNCTION__, ctx, unit ); } /* REPLACE MODULATE DECAL GL_BLEND * * ALPHA C = Cf C = Cf undef C = Cf * A = At A = AfAt A = AfAt * * LUMINANCE C = Ct C = CfCt undef C = Cf(1-Ct)+CcCt * A = Af A = Af A = Af * * LUMINANCE_ALPHA C = Ct C = CfCt undef C = Cf(1-Ct)+CcCt * A = At A = AfAt A = AfAt * * INTENSITY C = Ct C = CfCt undef C = Cf(1-Ct)+CcCt * A = At A = AfAt A = Af(1-At)+AcAt * * RGB C = Ct C = CfCt C = Ct C = Cf(1-Ct)+CcCt * A = Af A = Af A = Af A = Af * * RGBA C = Ct C = CfCt C = Cf(1-At)+CtAt C = Cf(1-Ct)+CcCt * A = At A = AfAt A = Af A = AfAt */ if ( unit == 0 ) { s &= ~MACH64_TEX_LIGHT_FCN_MASK; /* Set the texture environment state * Need to verify these are working correctly, but the * texenv Mesa demo seems to work. */ switch ( texUnit->EnvMode ) { case GL_REPLACE: switch ( format ) { case GL_ALPHA: case GL_LUMINANCE_ALPHA: case GL_INTENSITY: /* Not compliant - can't get At */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; default: s |= MACH64_TEX_LIGHT_FCN_REPLACE; } break; case GL_MODULATE: switch ( format ) { case GL_ALPHA: FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; case GL_RGB: case GL_LUMINANCE: /* These should be compliant */ s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; case GL_LUMINANCE_ALPHA: case GL_INTENSITY: FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; case GL_RGBA: /* Should fallback when blending enabled for complete compliance */ s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; default: s |= MACH64_TEX_LIGHT_FCN_MODULATE; } break; case GL_DECAL: switch ( format ) { case GL_RGBA: s |= MACH64_TEX_LIGHT_FCN_ALPHA_DECAL; break; case GL_RGB: s |= MACH64_TEX_LIGHT_FCN_REPLACE; break; case GL_ALPHA: case GL_LUMINANCE_ALPHA: /* undefined - disable texturing, pass fragment unmodified */ /* Also, pass fragment alpha instead of texture alpha */ s &= ~MACH64_TEX_MAP_AEN; s |= MACH64_TEXTURE_DISABLE; s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; case GL_LUMINANCE: case GL_INTENSITY: /* undefined - disable texturing, pass fragment unmodified */ s |= MACH64_TEXTURE_DISABLE; s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; default: s |= MACH64_TEX_LIGHT_FCN_MODULATE; } break; case GL_BLEND: /* GL_BLEND not supported by RagePRO, use software */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; case GL_ADD: case GL_COMBINE: FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); s |= MACH64_TEX_LIGHT_FCN_MODULATE; break; default: s |= MACH64_TEX_LIGHT_FCN_MODULATE; } if ( mmesa->setup.scale_3d_cntl != s ) { mmesa->setup.scale_3d_cntl = s; mmesa->dirty |= MACH64_UPLOAD_SCALE_3D_CNTL; } } else { /* blend = 0, modulate = 1 - initialize to blend */ mmesa->setup.tex_cntl &= ~MACH64_COMP_COMBINE_MODULATE; /* Set the texture composite function for multitexturing*/ switch ( texUnit->EnvMode ) { case GL_BLEND: /* GL_BLEND not supported by RagePRO, use software */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; break; case GL_MODULATE: /* Should fallback when blending enabled for complete compliance */ mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; break; case GL_REPLACE: switch ( format ) { case GL_ALPHA: mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; break; default: /* not supported by RagePRO */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; } break; case GL_DECAL: switch ( format ) { case GL_ALPHA: case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: case GL_INTENSITY: /* undefined, disable compositing and pass fragment unmodified */ mmesa->setup.tex_cntl &= ~MACH64_TEXTURE_COMPOSITE; break; default: /* not supported by RagePRO */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; } break; case GL_ADD: case GL_COMBINE: FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; break; default: mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; } } } static void mach64UpdateTextureUnit( struct gl_context *ctx, int unit ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); int source = mmesa->tmu_source[unit]; const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; const struct gl_texture_object *tObj = ctx->Texture.Unit[source]._Current; mach64TexObjPtr t = tObj->DriverData; GLuint d = mmesa->setup.dp_pix_width; GLuint s = mmesa->setup.scale_3d_cntl; assert(unit == 0 || unit == 1); /* only two tex units */ if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %p, %d ) enabled=0x%x 0x%x\n", __FUNCTION__, ctx, unit, ctx->Texture.Unit[0]._ReallyEnabled, ctx->Texture.Unit[1]._ReallyEnabled); } if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) { assert(t); /* should have driver tex data by now */ /* Fallback if there's a texture border */ if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) { FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); return; } /* Upload teximages */ if (t->base.dirty_images[0]) { mach64SetTexImages( mmesa, tObj ); mmesa->dirty |= (MACH64_UPLOAD_TEX0IMAGE << unit); } /* Bind to the given texture unit */ mmesa->CurrentTexObj[unit] = t; t->base.bound |= (1 << unit); if ( t->base.memBlock ) driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked! */ /* register setup */ if ( unit == 0 ) { d &= ~MACH64_SCALE_PIX_WIDTH_MASK; d |= (t->textureFormat << 28); s &= ~(MACH64_TEXTURE_DISABLE | MACH64_TEX_CACHE_SPLIT | MACH64_TEX_BLEND_FCN_MASK | MACH64_TEX_MAP_AEN); if ( mmesa->multitex ) { s |= MACH64_TEX_BLEND_FCN_TRILINEAR | MACH64_TEX_CACHE_SPLIT; } else if ( t->BilinearMin ) { s |= MACH64_TEX_BLEND_FCN_LINEAR; } else { s |= MACH64_TEX_BLEND_FCN_NEAREST; } if ( t->BilinearMag ) { s |= MACH64_BILINEAR_TEX_EN; } else { s &= ~MACH64_BILINEAR_TEX_EN; } if ( t->hasAlpha ) { s |= MACH64_TEX_MAP_AEN; } mmesa->setup.tex_cntl &= ~(MACH64_TEXTURE_CLAMP_S | MACH64_TEXTURE_CLAMP_T | MACH64_SECONDARY_STW); if ( t->ClampS ) { mmesa->setup.tex_cntl |= MACH64_TEXTURE_CLAMP_S; } if ( t->ClampT ) { mmesa->setup.tex_cntl |= MACH64_TEXTURE_CLAMP_T; } mmesa->setup.tex_size_pitch |= ((t->widthLog2 << 0) | (t->maxLog2 << 4) | (t->heightLog2 << 8)); } else { /* Enable texture mapping mode */ s &= ~MACH64_TEXTURE_DISABLE; d &= ~MACH64_COMPOSITE_PIX_WIDTH_MASK; d |= (t->textureFormat << 4); mmesa->setup.tex_cntl &= ~(MACH64_COMP_ALPHA | MACH64_SEC_TEX_CLAMP_S | MACH64_SEC_TEX_CLAMP_T); mmesa->setup.tex_cntl |= (MACH64_TEXTURE_COMPOSITE | MACH64_SECONDARY_STW); if ( t->BilinearMin ) { mmesa->setup.tex_cntl |= MACH64_COMP_BLEND_BILINEAR; } else { mmesa->setup.tex_cntl &= ~MACH64_COMP_BLEND_BILINEAR; } if ( t->BilinearMag ) { mmesa->setup.tex_cntl |= MACH64_COMP_FILTER_BILINEAR; } else { mmesa->setup.tex_cntl &= ~MACH64_COMP_FILTER_BILINEAR; } if ( t->hasAlpha ) { mmesa->setup.tex_cntl |= MACH64_COMP_ALPHA; } if ( t->ClampS ) { mmesa->setup.tex_cntl |= MACH64_SEC_TEX_CLAMP_S; } if ( t->ClampT ) { mmesa->setup.tex_cntl |= MACH64_SEC_TEX_CLAMP_T; } mmesa->setup.tex_size_pitch |= ((t->widthLog2 << 16) | (t->maxLog2 << 20) | (t->heightLog2 << 24)); } if ( mmesa->setup.scale_3d_cntl != s ) { mmesa->setup.scale_3d_cntl = s; mmesa->dirty |= MACH64_UPLOAD_SCALE_3D_CNTL; } if ( mmesa->setup.dp_pix_width != d ) { mmesa->setup.dp_pix_width = d; mmesa->dirty |= MACH64_UPLOAD_DP_PIX_WIDTH; } } else if (texUnit->_ReallyEnabled) { /* 3D or cube map texture enabled - fallback */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); } else { /* texture unit disabled */ } } /* Update the hardware texture state */ void mach64UpdateTextureState( struct gl_context *ctx ) { mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { fprintf( stderr, "%s( %p ) en=0x%x 0x%x\n", __FUNCTION__, ctx, ctx->Texture.Unit[0]._ReallyEnabled, ctx->Texture.Unit[1]._ReallyEnabled); } /* Clear any texturing fallbacks */ FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_FALSE ); /* Unbind any currently bound textures */ if ( mmesa->CurrentTexObj[0] ) mmesa->CurrentTexObj[0]->base.bound = 0; if ( mmesa->CurrentTexObj[1] ) mmesa->CurrentTexObj[1]->base.bound = 0; mmesa->CurrentTexObj[0] = NULL; mmesa->CurrentTexObj[1] = NULL; /* Disable all texturing until it is known to be good */ mmesa->setup.scale_3d_cntl |= MACH64_TEXTURE_DISABLE; mmesa->setup.scale_3d_cntl &= ~MACH64_TEX_MAP_AEN; mmesa->setup.tex_cntl &= ~MACH64_TEXTURE_COMPOSITE; mmesa->setup.tex_size_pitch = 0x00000000; mmesa->tmu_source[0] = 0; mmesa->tmu_source[1] = 1; mmesa->multitex = 0; if (ctx->Texture._EnabledUnits & 0x2) { /* unit 1 enabled */ if (ctx->Texture._EnabledUnits & 0x1) { /* units 0 and 1 enabled */ mmesa->multitex = 1; mach64UpdateTextureUnit( ctx, 0 ); mach64UpdateTextureEnv( ctx, 0 ); mach64UpdateTextureUnit( ctx, 1 ); mach64UpdateTextureEnv( ctx, 1 ); } else { mmesa->tmu_source[0] = 1; mmesa->tmu_source[1] = 0; mach64UpdateTextureUnit( ctx, 0 ); mach64UpdateTextureEnv( ctx, 0 ); } } else if (ctx->Texture._EnabledUnits & 0x1) { /* only unit 0 enabled */ mach64UpdateTextureUnit( ctx, 0 ); mach64UpdateTextureEnv( ctx, 0 ); } mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL | MACH64_UPLOAD_TEXTURE); } /* Due to the way we must program texture state into the Rage Pro, * we must leave these calculations to the absolute last minute. */ void mach64EmitTexStateLocked( mach64ContextPtr mmesa, mach64TexObjPtr t0, mach64TexObjPtr t1 ) { drm_mach64_sarea_t *sarea = mmesa->sarea; drm_mach64_context_regs_t *regs = &(mmesa->setup); /* for multitex, both textures must be local or AGP */ if ( t0 && t1 ) assert(t0->heap == t1->heap); if ( t0 ) { if (t0->heap == MACH64_CARD_HEAP) { #if ENABLE_PERF_BOXES mmesa->c_texsrc_card++; #endif mmesa->setup.tex_cntl &= ~MACH64_TEX_SRC_AGP; } else { #if ENABLE_PERF_BOXES mmesa->c_texsrc_agp++; #endif mmesa->setup.tex_cntl |= MACH64_TEX_SRC_AGP; } mmesa->setup.tex_offset = t0->bufAddr; } if ( t1 ) { mmesa->setup.secondary_tex_off = t1->bufAddr; } memcpy( &sarea->context_state.tex_size_pitch, ®s->tex_size_pitch, MACH64_NR_TEXTURE_REGS * sizeof(GLuint) ); }