diff options
Diffstat (limited to 'src/mesa/drivers/dri/r300/r300_texstate.c')
-rw-r--r-- | src/mesa/drivers/dri/r300/r300_texstate.c | 1390 |
1 files changed, 1390 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/r300/r300_texstate.c b/src/mesa/drivers/dri/r300/r300_texstate.c new file mode 100644 index 0000000000..6962bb3ddb --- /dev/null +++ b/src/mesa/drivers/dri/r300/r300_texstate.c @@ -0,0 +1,1390 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r300/r300_texstate.c,v 1.3 2003/02/15 22:18:47 dawes Exp $ */ +/* +Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + +The Weather Channel (TM) funded Tungsten Graphics to develop the +initial release of the Radeon 8500 driver under the XFree86 license. +This notice must be preserved. + +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 THE COPYRIGHT OWNER(S) AND/OR ITS 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: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "macros.h" +#include "texformat.h" +#include "enums.h" + +#include "r300_context.h" +#include "r300_state.h" +#include "radeon_ioctl.h" +//#include "r300_swtcl.h" +#include "r300_tex.h" +//#include "r300_tcl.h" + +#define R200_TXFORMAT_A8 R200_TXFORMAT_I8 +#define R200_TXFORMAT_L8 R200_TXFORMAT_I8 +#define R200_TXFORMAT_AL88 R200_TXFORMAT_AI88 +#define R200_TXFORMAT_YCBCR R200_TXFORMAT_YVYU422 +#define R200_TXFORMAT_YCBCR_REV R200_TXFORMAT_VYUY422 + +#define _COLOR(f) \ + [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, 0 } +#define _COLOR_REV(f) \ + [ MESA_FORMAT_ ## f ## _REV ] = { R200_TXFORMAT_ ## f, 0 } +#define _ALPHA(f) \ + [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f | R200_TXFORMAT_ALPHA_IN_MAP, 0 } +#define _ALPHA_REV(f) \ + [ MESA_FORMAT_ ## f ## _REV ] = { R200_TXFORMAT_ ## f | R200_TXFORMAT_ALPHA_IN_MAP, 0 } +#define _YUV(f) \ + [ MESA_FORMAT_ ## f ] = { R200_TXFORMAT_ ## f, R200_YUV_TO_RGB } +#define _INVALID(f) \ + [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 } +#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \ + && (tx_table[f].format != 0xffffffff) ) + +static const struct { + GLuint format, filter; +} tx_table[] = { +_ALPHA(RGBA8888), + _ALPHA_REV(RGBA8888), + _ALPHA(ARGB8888), + _ALPHA_REV(ARGB8888), + _INVALID(RGB888), + _COLOR(RGB565), + _COLOR_REV(RGB565), + _ALPHA(ARGB4444), + _ALPHA_REV(ARGB4444), + _ALPHA(ARGB1555), + _ALPHA_REV(ARGB1555), + _ALPHA(AL88), + _ALPHA_REV(AL88), + _ALPHA(A8), + _COLOR(L8), + _ALPHA(I8), _INVALID(CI8), _YUV(YCBCR), _YUV(YCBCR_REV),}; + +#undef _COLOR +#undef _ALPHA +#undef _INVALID + +/** + * This function computes the number of bytes of storage needed for + * the given texture object (all mipmap levels, all cube faces). + * The \c image[face][level].x/y/width/height parameters for upload/blitting + * are computed here. \c filter, \c format, etc. will be set here + * too. + * + * \param rmesa Context pointer + * \param tObj GL texture object whose images are to be posted to + * hardware state. + */ +static void r300SetTexImages(r300ContextPtr rmesa, + struct gl_texture_object *tObj) +{ + r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + const struct gl_texture_image *baseImage = + tObj->Image[0][tObj->BaseLevel]; + GLint curOffset; + GLint i; + GLint numLevels; + GLint log2Width, log2Height, log2Depth; + + /* Set the hardware texture format + */ + + t->format &= ~(R200_TXFORMAT_FORMAT_MASK | + R200_TXFORMAT_ALPHA_IN_MAP); + t->filter &= ~R200_YUV_TO_RGB; + + if (VALID_FORMAT(baseImage->TexFormat->MesaFormat)) { + t->format |= + tx_table[baseImage->TexFormat->MesaFormat].format; + t->filter |= + tx_table[baseImage->TexFormat->MesaFormat].filter; + } else { + _mesa_problem(NULL, "unexpected texture format in %s", + __FUNCTION__); + return; + } + + /* Compute which mipmap levels we really want to send to the hardware. + */ + + driCalculateTextureFirstLastLevel((driTextureObject *) t); + log2Width = tObj->Image[0][t->base.firstLevel]->WidthLog2; + log2Height = tObj->Image[0][t->base.firstLevel]->HeightLog2; + log2Depth = tObj->Image[0][t->base.firstLevel]->DepthLog2; + + numLevels = t->base.lastLevel - t->base.firstLevel + 1; + + assert(numLevels <= RADEON_MAX_TEXTURE_LEVELS); + + /* Calculate mipmap offsets and dimensions for blitting (uploading) + * The idea is that we lay out the mipmap levels within a block of + * memory organized as a rectangle of width BLIT_WIDTH_BYTES. + */ + curOffset = 0; + + for (i = 0; i < numLevels; i++) { + const struct gl_texture_image *texImage; + GLuint size; + + texImage = tObj->Image[0][i + t->base.firstLevel]; + if (!texImage) + break; + + /* find image size in bytes */ + if (texImage->IsCompressed) { + size = texImage->CompressedSize; + } else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { + size = + ((texImage->Width * + texImage->TexFormat->TexelBytes + 63) + & ~63) * texImage->Height; + } else { + int w = + texImage->Width * texImage->TexFormat->TexelBytes; + if (w < 32) + w = 32; + size = w * texImage->Height * texImage->Depth; + } + assert(size > 0); + + /* Align to 32-byte offset. It is faster to do this unconditionally + * (no branch penalty). + */ + + curOffset = (curOffset + 0x1f) & ~0x1f; + + t->image[0][i].x = curOffset % BLIT_WIDTH_BYTES; + t->image[0][i].y = curOffset / BLIT_WIDTH_BYTES; + t->image[0][i].width = MIN2(size, BLIT_WIDTH_BYTES); + t->image[0][i].height = size / t->image[0][i].width; + +#if 0 + /* for debugging only and only applicable to non-rectangle targets */ + assert(size % t->image[0][i].width == 0); + assert(t->image[0][i].x == 0 + || (size < BLIT_WIDTH_BYTES + && t->image[0][i].height == 1)); +#endif + + if (0) + fprintf(stderr, + "level %d: %dx%d x=%d y=%d w=%d h=%d size=%d at %d\n", + i, texImage->Width, texImage->Height, + t->image[0][i].x, t->image[0][i].y, + t->image[0][i].width, t->image[0][i].height, + size, curOffset); + + curOffset += size; + + } + + /* Align the total size of texture memory block. + */ + t->base.totalSize = + (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; + + /* Setup remaining cube face blits, if needed */ + if (tObj->Target == GL_TEXTURE_CUBE_MAP) { + /* Round totalSize up to multiple of BLIT_WIDTH_BYTES */ + const GLuint faceSize = + (t->base.totalSize + BLIT_WIDTH_BYTES - 1) + & ~(BLIT_WIDTH_BYTES - 1); + const GLuint lines = faceSize / BLIT_WIDTH_BYTES; + GLuint face; + /* reuse face 0 x/y/width/height - just adjust y */ + for (face = 1; face < 6; face++) { + for (i = 0; i < numLevels; i++) { + t->image[face][i].x = t->image[0][i].x; + t->image[face][i].y = + t->image[0][i].y + face * lines; + t->image[face][i].width = t->image[0][i].width; + t->image[face][i].height = + t->image[0][i].height; + } + } + t->base.totalSize = 6 * faceSize; /* total texmem needed */ + } + + /* Hardware state: + */ + t->filter &= ~R200_MAX_MIP_LEVEL_MASK; + t->filter |= (numLevels - 1) << R200_MAX_MIP_LEVEL_SHIFT; + + t->format &= ~(R200_TXFORMAT_WIDTH_MASK | + R200_TXFORMAT_HEIGHT_MASK | + R200_TXFORMAT_CUBIC_MAP_ENABLE | + R200_TXFORMAT_F5_WIDTH_MASK | + R200_TXFORMAT_F5_HEIGHT_MASK); + t->format |= ((log2Width << R200_TXFORMAT_WIDTH_SHIFT) | + (log2Height << R200_TXFORMAT_HEIGHT_SHIFT)); + + #if 0 + t->format_x &= ~(R200_DEPTH_LOG2_MASK | R200_TEXCOORD_MASK); + if (tObj->Target == GL_TEXTURE_3D) { + t->format_x |= (log2Depth << R200_DEPTH_LOG2_SHIFT); + t->format_x |= R200_TEXCOORD_VOLUME; + } else if (tObj->Target == GL_TEXTURE_CUBE_MAP) { + ASSERT(log2Width == log2height); + t->format |= ((log2Width << R200_TXFORMAT_F5_WIDTH_SHIFT) | + (log2Height << R200_TXFORMAT_F5_HEIGHT_SHIFT) + | (R200_TXFORMAT_CUBIC_MAP_ENABLE)); + t->format_x |= R200_TEXCOORD_CUBIC_ENV; + t->pp_cubic_faces = ((log2Width << R200_FACE_WIDTH_1_SHIFT) | + (log2Height << R200_FACE_HEIGHT_1_SHIFT) | + (log2Width << R200_FACE_WIDTH_2_SHIFT) | + (log2Height << R200_FACE_HEIGHT_2_SHIFT) | + (log2Width << R200_FACE_WIDTH_3_SHIFT) | + (log2Height << R200_FACE_HEIGHT_3_SHIFT) | + (log2Width << R200_FACE_WIDTH_4_SHIFT) | + (log2Height << R200_FACE_HEIGHT_4_SHIFT)); + } + #endif + + t->size = (((tObj->Image[0][t->base.firstLevel]->Width - 1) << 0) | + ((tObj->Image[0][t->base.firstLevel]->Height - + 1) << 16)); + + /* Only need to round to nearest 32 for textures, but the blitter + * requires 64-byte aligned pitches, and we may/may not need the + * blitter. NPOT only! + */ + if (baseImage->IsCompressed) + t->pitch = + (tObj->Image[0][t->base.firstLevel]->Width + 63) & ~(63); + else + t->pitch = + ((tObj->Image[0][t->base.firstLevel]->Width * + baseImage->TexFormat->TexelBytes) + 63) & ~(63); + t->pitch -= 32; + + t->dirty_state = TEX_ALL; + + /* FYI: r300UploadTexImages( rmesa, t ) used to be called here */ +} + +/* ================================================================ + * Texture combine functions + */ + +/* GL_ARB_texture_env_combine support + */ + +/* The color tables have combine functions for GL_SRC_COLOR, + * GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. + */ +static GLuint r300_register_color[][R200_MAX_TEXTURE_UNITS] = { + { + R200_TXC_ARG_A_R0_COLOR, + R200_TXC_ARG_A_R1_COLOR, + R200_TXC_ARG_A_R2_COLOR, + R200_TXC_ARG_A_R3_COLOR, + R200_TXC_ARG_A_R4_COLOR, + R200_TXC_ARG_A_R5_COLOR}, + { + R200_TXC_ARG_A_R0_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R1_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R2_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R3_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R4_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R5_COLOR | R200_TXC_COMP_ARG_A}, + { + R200_TXC_ARG_A_R0_ALPHA, + R200_TXC_ARG_A_R1_ALPHA, + R200_TXC_ARG_A_R2_ALPHA, + R200_TXC_ARG_A_R3_ALPHA, + R200_TXC_ARG_A_R4_ALPHA, + R200_TXC_ARG_A_R5_ALPHA}, + { + R200_TXC_ARG_A_R0_ALPHA | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R1_ALPHA | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R2_ALPHA | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R3_ALPHA | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R4_ALPHA | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_R5_ALPHA | R200_TXC_COMP_ARG_A}, +}; + +static GLuint r300_tfactor_color[] = { + R200_TXC_ARG_A_TFACTOR_COLOR, + R200_TXC_ARG_A_TFACTOR_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_TFACTOR_ALPHA, + R200_TXC_ARG_A_TFACTOR_ALPHA | R200_TXC_COMP_ARG_A +}; + +static GLuint r300_primary_color[] = { + R200_TXC_ARG_A_DIFFUSE_COLOR, + R200_TXC_ARG_A_DIFFUSE_COLOR | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_DIFFUSE_ALPHA, + R200_TXC_ARG_A_DIFFUSE_ALPHA | R200_TXC_COMP_ARG_A +}; + +/* GL_ZERO table - indices 0-3 + * GL_ONE table - indices 1-4 + */ +static GLuint r300_zero_color[] = { + R200_TXC_ARG_A_ZERO, + R200_TXC_ARG_A_ZERO | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_ZERO, + R200_TXC_ARG_A_ZERO | R200_TXC_COMP_ARG_A, + R200_TXC_ARG_A_ZERO +}; + +/* The alpha tables only have GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. + */ +static GLuint r300_register_alpha[][R200_MAX_TEXTURE_UNITS] = { + { + R200_TXA_ARG_A_R0_ALPHA, + R200_TXA_ARG_A_R1_ALPHA, + R200_TXA_ARG_A_R2_ALPHA, + R200_TXA_ARG_A_R3_ALPHA, + R200_TXA_ARG_A_R4_ALPHA, + R200_TXA_ARG_A_R5_ALPHA}, + { + R200_TXA_ARG_A_R0_ALPHA | R200_TXA_COMP_ARG_A, + R200_TXA_ARG_A_R1_ALPHA | R200_TXA_COMP_ARG_A, + R200_TXA_ARG_A_R2_ALPHA | R200_TXA_COMP_ARG_A, + R200_TXA_ARG_A_R3_ALPHA | R200_TXA_COMP_ARG_A, + R200_TXA_ARG_A_R4_ALPHA | R200_TXA_COMP_ARG_A, + R200_TXA_ARG_A_R5_ALPHA | R200_TXA_COMP_ARG_A}, +}; + +static GLuint r300_tfactor_alpha[] = { + R200_TXA_ARG_A_TFACTOR_ALPHA, + R200_TXA_ARG_A_TFACTOR_ALPHA | R200_TXA_COMP_ARG_A +}; + +static GLuint r300_primary_alpha[] = { + R200_TXA_ARG_A_DIFFUSE_ALPHA, + R200_TXA_ARG_A_DIFFUSE_ALPHA | R200_TXA_COMP_ARG_A +}; + +/* GL_ZERO table - indices 0-1 + * GL_ONE table - indices 1-2 + */ +static GLuint r300_zero_alpha[] = { + R200_TXA_ARG_A_ZERO, + R200_TXA_ARG_A_ZERO | R200_TXA_COMP_ARG_A, + R200_TXA_ARG_A_ZERO, +}; + +/* Extract the arg from slot A, shift it into the correct argument slot + * and set the corresponding complement bit. + */ +#define R200_COLOR_ARG( n, arg ) \ +do { \ + color_combine |= \ + ((color_arg[n] & R200_TXC_ARG_A_MASK) \ + << R200_TXC_ARG_##arg##_SHIFT); \ + color_combine |= \ + ((color_arg[n] >> R200_TXC_COMP_ARG_A_SHIFT) \ + << R200_TXC_COMP_ARG_##arg##_SHIFT); \ +} while (0) + +#define R200_ALPHA_ARG( n, arg ) \ +do { \ + alpha_combine |= \ + ((alpha_arg[n] & R200_TXA_ARG_A_MASK) \ + << R200_TXA_ARG_##arg##_SHIFT); \ + alpha_combine |= \ + ((alpha_arg[n] >> R200_TXA_COMP_ARG_A_SHIFT) \ + << R200_TXA_COMP_ARG_##arg##_SHIFT); \ +} while (0) + +/* ================================================================ + * Texture unit state management + */ + +static GLboolean r300UpdateTextureEnv(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLuint color_combine, alpha_combine; + + #if 0 /* disable for now.. */ + GLuint color_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] & + ~(R200_TXC_SCALE_MASK); + GLuint alpha_scale = rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] & + ~(R200_TXA_DOT_ALPHA | R200_TXA_SCALE_MASK); + + /* texUnit->_Current can be NULL if and only if the texture unit is + * not actually enabled. + */ + assert((texUnit->_ReallyEnabled == 0) + || (texUnit->_Current != NULL)); + + if (RADEON_DEBUG & DEBUG_TEXTURE) { + fprintf(stderr, "%s( %p, %d )\n", __FUNCTION__, (void *)ctx, + unit); + } + + /* Set the texture environment state. Isn't this nice and clean? + * The chip will automagically set the texture alpha to 0xff when + * the texture format does not include an alpha component. This + * reduces the amount of special-casing we have to do, alpha-only + * textures being a notable exception. + */ + /* Don't cache these results. + */ + rmesa->state.texture.unit[unit].format = 0; + rmesa->state.texture.unit[unit].envMode = 0; + + if (!texUnit->_ReallyEnabled) { + if (unit == 0) { + color_combine = + R200_TXC_ARG_A_ZERO | R200_TXC_ARG_B_ZERO | + R200_TXC_ARG_C_DIFFUSE_COLOR | R200_TXC_OP_MADD; + alpha_combine = + R200_TXA_ARG_A_ZERO | R200_TXA_ARG_B_ZERO | + R200_TXA_ARG_C_DIFFUSE_ALPHA | R200_TXA_OP_MADD; + } else { + color_combine = + R200_TXC_ARG_A_ZERO | R200_TXC_ARG_B_ZERO | + R200_TXC_ARG_C_R0_COLOR | R200_TXC_OP_MADD; + alpha_combine = + R200_TXA_ARG_A_ZERO | R200_TXA_ARG_B_ZERO | + R200_TXA_ARG_C_R0_ALPHA | R200_TXA_OP_MADD; + } + } else { + GLuint color_arg[3], alpha_arg[3]; + GLuint i; + const GLuint numColorArgs = + texUnit->_CurrentCombine->_NumArgsRGB; + const GLuint numAlphaArgs = texUnit->_CurrentCombine->_NumArgsA; + GLuint RGBshift = texUnit->_CurrentCombine->ScaleShiftRGB; + GLuint Ashift = texUnit->_CurrentCombine->ScaleShiftA; + + /* Step 1: + * Extract the color and alpha combine function arguments. + */ + for (i = 0; i < numColorArgs; i++) { + const GLint op = + texUnit->_CurrentCombine->OperandRGB[i] - + GL_SRC_COLOR; + assert(op >= 0); + assert(op <= 3); + switch (texUnit->_CurrentCombine->SourceRGB[i]) { + case GL_TEXTURE: + color_arg[i] = r300_register_color[op][unit]; + break; + case GL_CONSTANT: + color_arg[i] = r300_tfactor_color[op]; + break; + case GL_PRIMARY_COLOR: + color_arg[i] = r300_primary_color[op]; + break; + case GL_PREVIOUS: + if (unit == 0) + color_arg[i] = r300_primary_color[op]; + else + color_arg[i] = + r300_register_color[op][0]; + break; + case GL_ZERO: + color_arg[i] = r300_zero_color[op]; + break; + case GL_ONE: + color_arg[i] = r300_zero_color[op + 1]; + break; + default: + return GL_FALSE; + } + } + + for (i = 0; i < numAlphaArgs; i++) { + const GLint op = + texUnit->_CurrentCombine->OperandA[i] - + GL_SRC_ALPHA; + assert(op >= 0); + assert(op <= 1); + switch (texUnit->_CurrentCombine->SourceA[i]) { + case GL_TEXTURE: + alpha_arg[i] = r300_register_alpha[op][unit]; + break; + case GL_CONSTANT: + alpha_arg[i] = r300_tfactor_alpha[op]; + break; + case GL_PRIMARY_COLOR: + alpha_arg[i] = r300_primary_alpha[op]; + break; + case GL_PREVIOUS: + if (unit == 0) + alpha_arg[i] = r300_primary_alpha[op]; + else + alpha_arg[i] = + r300_register_alpha[op][0]; + break; + case GL_ZERO: + alpha_arg[i] = r300_zero_alpha[op]; + break; + case GL_ONE: + alpha_arg[i] = r300_zero_alpha[op + 1]; + break; + default: + return GL_FALSE; + } + } + + /* Step 2: + * Build up the color and alpha combine functions. + */ + switch (texUnit->_CurrentCombine->ModeRGB) { + case GL_REPLACE: + color_combine = (R200_TXC_ARG_A_ZERO | + R200_TXC_ARG_B_ZERO | + R200_TXC_OP_MADD); + R200_COLOR_ARG(0, C); + break; + case GL_MODULATE: + color_combine = (R200_TXC_ARG_C_ZERO | + R200_TXC_OP_MADD); + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, B); + break; + case GL_ADD: + color_combine = (R200_TXC_ARG_B_ZERO | + R200_TXC_COMP_ARG_B | + R200_TXC_OP_MADD); + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, C); + break; + case GL_ADD_SIGNED: + color_combine = (R200_TXC_ARG_B_ZERO | R200_TXC_COMP_ARG_B | R200_TXC_BIAS_ARG_C | /* new */ + R200_TXC_OP_MADD); /* was ADDSIGNED */ + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, C); + break; + case GL_SUBTRACT: + color_combine = (R200_TXC_ARG_B_ZERO | + R200_TXC_COMP_ARG_B | + R200_TXC_NEG_ARG_C | R200_TXC_OP_MADD); + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, C); + break; + case GL_INTERPOLATE: + color_combine = (R200_TXC_OP_LERP); + R200_COLOR_ARG(0, B); + R200_COLOR_ARG(1, A); + R200_COLOR_ARG(2, C); + break; + + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + /* The EXT version of the DOT3 extension does not support the + * scale factor, but the ARB version (and the version in OpenGL + * 1.3) does. + */ + RGBshift = 0; + /* FALLTHROUGH */ + + case GL_DOT3_RGB: + case GL_DOT3_RGBA: + /* DOT3 works differently on R200 than on R100. On R100, just + * setting the DOT3 mode did everything for you. On R200, the + * driver has to enable the biasing and scale in the inputs to + * put them in the proper [-1,1] range. This is what the 4x and + * the -0.5 in the DOT3 spec do. The post-scale is then set + * normally. + */ + + color_combine = (R200_TXC_ARG_C_ZERO | + R200_TXC_OP_DOT3 | + R200_TXC_BIAS_ARG_A | + R200_TXC_BIAS_ARG_B | + R200_TXC_SCALE_ARG_A | + R200_TXC_SCALE_ARG_B); + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, B); + break; + + case GL_MODULATE_ADD_ATI: + color_combine = (R200_TXC_OP_MADD); + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, C); + R200_COLOR_ARG(2, B); + break; + case GL_MODULATE_SIGNED_ADD_ATI: + color_combine = (R200_TXC_BIAS_ARG_C | /* new */ + R200_TXC_OP_MADD); /* was ADDSIGNED */ + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, C); + R200_COLOR_ARG(2, B); + break; + case GL_MODULATE_SUBTRACT_ATI: + color_combine = (R200_TXC_NEG_ARG_C | R200_TXC_OP_MADD); + R200_COLOR_ARG(0, A); + R200_COLOR_ARG(1, C); + R200_COLOR_ARG(2, B); + break; + default: + return GL_FALSE; + } + + switch (texUnit->_CurrentCombine->ModeA) { + case GL_REPLACE: + alpha_combine = (R200_TXA_ARG_A_ZERO | + R200_TXA_ARG_B_ZERO | + R200_TXA_OP_MADD); + R200_ALPHA_ARG(0, C); + break; + case GL_MODULATE: + alpha_combine = (R200_TXA_ARG_C_ZERO | + R200_TXA_OP_MADD); + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, B); + break; + case GL_ADD: + alpha_combine = (R200_TXA_ARG_B_ZERO | + R200_TXA_COMP_ARG_B | + R200_TXA_OP_MADD); + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, C); + break; + case GL_ADD_SIGNED: + alpha_combine = (R200_TXA_ARG_B_ZERO | R200_TXA_COMP_ARG_B | R200_TXA_BIAS_ARG_C | /* new */ + R200_TXA_OP_MADD); /* was ADDSIGNED */ + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, C); + break; + case GL_SUBTRACT: + alpha_combine = (R200_TXA_ARG_B_ZERO | + R200_TXA_COMP_ARG_B | + R200_TXA_NEG_ARG_C | R200_TXA_OP_MADD); + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, C); + break; + case GL_INTERPOLATE: + alpha_combine = (R200_TXA_OP_LERP); + R200_ALPHA_ARG(0, B); + R200_ALPHA_ARG(1, A); + R200_ALPHA_ARG(2, C); + break; + + case GL_MODULATE_ADD_ATI: + alpha_combine = (R200_TXA_OP_MADD); + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, C); + R200_ALPHA_ARG(2, B); + break; + case GL_MODULATE_SIGNED_ADD_ATI: + alpha_combine = (R200_TXA_BIAS_ARG_C | /* new */ + R200_TXA_OP_MADD); /* was ADDSIGNED */ + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, C); + R200_ALPHA_ARG(2, B); + break; + case GL_MODULATE_SUBTRACT_ATI: + alpha_combine = (R200_TXA_NEG_ARG_C | R200_TXA_OP_MADD); + R200_ALPHA_ARG(0, A); + R200_ALPHA_ARG(1, C); + R200_ALPHA_ARG(2, B); + break; + default: + return GL_FALSE; + } + + if ((texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA_EXT) + || (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA)) { + alpha_scale |= R200_TXA_DOT_ALPHA; + Ashift = RGBshift; + } + + /* Step 3: + * Apply the scale factor. + */ + color_scale |= (RGBshift << R200_TXC_SCALE_SHIFT); + alpha_scale |= (Ashift << R200_TXA_SCALE_SHIFT); + + /* All done! + */ + } + + if (rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND] != color_combine || + rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND] != alpha_combine || + rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] != color_scale || + rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] != alpha_scale) { + R300_STATECHANGE(rmesa, pix[unit]); + rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND] = color_combine; + rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND] = alpha_combine; + rmesa->hw.pix[unit].cmd[PIX_PP_TXCBLEND2] = color_scale; + rmesa->hw.pix[unit].cmd[PIX_PP_TXABLEND2] = alpha_scale; + } + + #endif + + return GL_TRUE; +} + +#define TEXOBJ_TXFILTER_MASK (R200_MAX_MIP_LEVEL_MASK | \ + R200_MIN_FILTER_MASK | \ + R200_MAG_FILTER_MASK | \ + R200_MAX_ANISO_MASK | \ + R200_YUV_TO_RGB | \ + R200_YUV_TEMPERATURE_MASK | \ + R200_CLAMP_S_MASK | \ + R200_CLAMP_T_MASK | \ + R200_BORDER_MODE_D3D ) + +#define TEXOBJ_TXFORMAT_MASK (R200_TXFORMAT_WIDTH_MASK | \ + R200_TXFORMAT_HEIGHT_MASK | \ + R200_TXFORMAT_FORMAT_MASK | \ + R200_TXFORMAT_F5_WIDTH_MASK | \ + R200_TXFORMAT_F5_HEIGHT_MASK | \ + R200_TXFORMAT_ALPHA_IN_MAP | \ + R200_TXFORMAT_CUBIC_MAP_ENABLE | \ + R200_TXFORMAT_NON_POWER2) + +#define TEXOBJ_TXFORMAT_X_MASK (R200_DEPTH_LOG2_MASK | \ + R200_TEXCOORD_MASK | \ + R200_CLAMP_Q_MASK | \ + R200_VOLUME_FILTER_MASK) + +static void import_tex_obj_state(r300ContextPtr rmesa, + int unit, r300TexObjPtr texobj) +{ + #if 0 /* needs fixing.. or should be done elsewhere */ + GLuint *cmd = R300_DB_STATE(tex[unit]); + + cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK; + cmd[TEX_PP_TXFILTER] |= texobj->filter & TEXOBJ_TXFILTER_MASK; + cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK; + cmd[TEX_PP_TXFORMAT] |= texobj->format & TEXOBJ_TXFORMAT_MASK; + cmd[TEX_PP_TXFORMAT_X] &= ~TEXOBJ_TXFORMAT_X_MASK; + cmd[TEX_PP_TXFORMAT_X] |= + texobj->format_x & TEXOBJ_TXFORMAT_X_MASK; + cmd[TEX_PP_TXSIZE] = texobj->size; /* NPOT only! */ + cmd[TEX_PP_TXPITCH] = texobj->pitch; /* NPOT only! */ + cmd[TEX_PP_TXOFFSET] = texobj->pp_txoffset; + cmd[TEX_PP_BORDER_COLOR] = texobj->pp_border_color; + R200_DB_STATECHANGE(rmesa, &rmesa->hw.tex[unit]); + + if (texobj->base.tObj->Target == GL_TEXTURE_CUBE_MAP) { + GLuint *cube_cmd = R200_DB_STATE(cube[unit]); + GLuint bytesPerFace = texobj->base.totalSize / 6; + ASSERT(texobj->totalSize % 6 == 0); + cube_cmd[CUBE_PP_CUBIC_FACES] = texobj->pp_cubic_faces; + cube_cmd[CUBE_PP_CUBIC_OFFSET_F1] = + texobj->pp_txoffset + 1 * bytesPerFace; + cube_cmd[CUBE_PP_CUBIC_OFFSET_F2] = + texobj->pp_txoffset + 2 * bytesPerFace; + cube_cmd[CUBE_PP_CUBIC_OFFSET_F3] = + texobj->pp_txoffset + 3 * bytesPerFace; + cube_cmd[CUBE_PP_CUBIC_OFFSET_F4] = + texobj->pp_txoffset + 4 * bytesPerFace; + cube_cmd[CUBE_PP_CUBIC_OFFSET_F5] = + texobj->pp_txoffset + 5 * bytesPerFace; + R200_DB_STATECHANGE(rmesa, &rmesa->hw.cube[unit]); + } + + texobj->dirty_state &= ~(1 << unit); + #endif +} + +static void set_texgen_matrix(r300ContextPtr rmesa, + GLuint unit, + const GLfloat * s_plane, + const GLfloat * t_plane, const GLfloat * r_plane) +{ + static const GLfloat scale_identity[4] = { 1, 1, 1, 1 }; + + if (!TEST_EQ_4V(s_plane, scale_identity) || + !TEST_EQ_4V(t_plane, scale_identity) || + !TEST_EQ_4V(r_plane, scale_identity)) { + rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE << unit; + rmesa->TexGenMatrix[unit].m[0] = s_plane[0]; + rmesa->TexGenMatrix[unit].m[4] = s_plane[1]; + rmesa->TexGenMatrix[unit].m[8] = s_plane[2]; + rmesa->TexGenMatrix[unit].m[12] = s_plane[3]; + + rmesa->TexGenMatrix[unit].m[1] = t_plane[0]; + rmesa->TexGenMatrix[unit].m[5] = t_plane[1]; + rmesa->TexGenMatrix[unit].m[9] = t_plane[2]; + rmesa->TexGenMatrix[unit].m[13] = t_plane[3]; + + /* NOTE: r_plane goes in the 4th row, not 3rd! */ + rmesa->TexGenMatrix[unit].m[3] = r_plane[0]; + rmesa->TexGenMatrix[unit].m[7] = r_plane[1]; + rmesa->TexGenMatrix[unit].m[11] = r_plane[2]; + rmesa->TexGenMatrix[unit].m[15] = r_plane[3]; + + //rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } +} + +/* Need this special matrix to get correct reflection map coords */ +static void set_texgen_reflection_matrix(r300ContextPtr rmesa, GLuint unit) +{ + static const GLfloat m[16] = { + -1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 0, -1, + 0, 0, -1, 0 + }; + _math_matrix_loadf(&(rmesa->TexGenMatrix[unit]), m); + _math_matrix_analyse(&(rmesa->TexGenMatrix[unit])); + rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE << unit; +} + +/* Need this special matrix to get correct normal map coords */ +static void set_texgen_normal_map_matrix(r300ContextPtr rmesa, GLuint unit) +{ + static const GLfloat m[16] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1, + 0, 0, 1, 0 + }; + _math_matrix_loadf(&(rmesa->TexGenMatrix[unit]), m); + _math_matrix_analyse(&(rmesa->TexGenMatrix[unit])); + rmesa->TexGenEnabled |= R200_TEXMAT_0_ENABLE << unit; +} + +/* Ignoring the Q texcoord for now. + * + * Returns GL_FALSE if fallback required. + */ +static GLboolean r300_validate_texgen(GLcontext * ctx, GLuint unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLuint inputshift = R200_TEXGEN_0_INPUT_SHIFT + unit * 4; + GLuint tmp = rmesa->TexGenEnabled; + + rmesa->TexGenCompSel &= ~(R200_OUTPUT_TEX_0 << unit); + rmesa->TexGenEnabled &= ~(R200_TEXGEN_TEXMAT_0_ENABLE << unit); + rmesa->TexGenEnabled &= ~(R200_TEXMAT_0_ENABLE << unit); + rmesa->TexGenInputs &= ~(R200_TEXGEN_INPUT_MASK << inputshift); + rmesa->TexGenNeedNormals[unit] = 0; + + if (0) + fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit); + + if ((texUnit->TexGenEnabled & (S_BIT | T_BIT | R_BIT)) == 0) { + /* Disabled, no fallback: + */ + rmesa->TexGenInputs |= + (R200_TEXGEN_INPUT_TEXCOORD_0 + unit) << inputshift; + return GL_TRUE; + } else if (texUnit->TexGenEnabled & Q_BIT) { + /* Very easy to do this, in fact would remove a fallback case + * elsewhere, but I haven't done it yet... Fallback: + */ + /*fprintf(stderr, "fallback Q_BIT\n"); */ + return GL_FALSE; + } else if (texUnit->TexGenEnabled == (S_BIT | T_BIT) && + texUnit->GenModeS == texUnit->GenModeT) { + /* OK */ + rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit; + /* continue */ + } else if (texUnit->TexGenEnabled == (S_BIT | T_BIT | R_BIT) && + texUnit->GenModeS == texUnit->GenModeT && + texUnit->GenModeT == texUnit->GenModeR) { + /* OK */ + rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit; + /* continue */ + } else { + /* Mixed modes, fallback: + */ + /* fprintf(stderr, "fallback mixed texgen\n"); */ + return GL_FALSE; + } + + rmesa->TexGenEnabled |= R200_TEXGEN_TEXMAT_0_ENABLE << unit; + + switch (texUnit->GenModeS) { + case GL_OBJECT_LINEAR: + rmesa->TexGenInputs |= R200_TEXGEN_INPUT_OBJ << inputshift; + set_texgen_matrix(rmesa, unit, + texUnit->ObjectPlaneS, + texUnit->ObjectPlaneT, texUnit->ObjectPlaneR); + break; + + case GL_EYE_LINEAR: + rmesa->TexGenInputs |= R200_TEXGEN_INPUT_EYE << inputshift; + set_texgen_matrix(rmesa, unit, + texUnit->EyePlaneS, + texUnit->EyePlaneT, texUnit->EyePlaneR); + break; + + case GL_REFLECTION_MAP_NV: + rmesa->TexGenNeedNormals[unit] = GL_TRUE; + rmesa->TexGenInputs |= + R200_TEXGEN_INPUT_EYE_REFLECT << inputshift; + set_texgen_reflection_matrix(rmesa, unit); + break; + + case GL_NORMAL_MAP_NV: + rmesa->TexGenNeedNormals[unit] = GL_TRUE; + rmesa->TexGenInputs |= + R200_TEXGEN_INPUT_EYE_NORMAL << inputshift; + set_texgen_normal_map_matrix(rmesa, unit); + break; + + case GL_SPHERE_MAP: + rmesa->TexGenNeedNormals[unit] = GL_TRUE; + rmesa->TexGenInputs |= R200_TEXGEN_INPUT_SPHERE << inputshift; + break; + + default: + /* Unsupported mode, fallback: + */ + /* fprintf(stderr, "fallback unsupported texgen\n"); */ + return GL_FALSE; + } + + rmesa->TexGenCompSel |= R200_OUTPUT_TEX_0 << unit; + + if (tmp != rmesa->TexGenEnabled) { + //rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } + + return GL_TRUE; +} + +static void disable_tex(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + + #if 0 /* This needs to be redone.. or done elsewhere */ + if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE << unit)) { + /* Texture unit disabled */ + if (rmesa->state.texture.unit[unit].texobj != NULL) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + rmesa->state.texture.unit[unit].texobj->base.bound &= + ~(1UL << unit); + rmesa->state.texture.unit[unit].texobj = NULL; + } + + R300_STATECHANGE(rmesa, ctx); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~((R200_TEX_0_ENABLE | + R200_TEX_BLEND_0_ENABLE) << + unit); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_BLEND_0_ENABLE; + + R300_STATECHANGE(rmesa, tcl); + rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] &= + ~(7 << (unit * 3)); + + if (rmesa->radeon.TclFallback & (RADEON_TCL_FALLBACK_TEXGEN_0 << unit)) { + TCL_FALLBACK(ctx, (RADEON_TCL_FALLBACK_TEXGEN_0 << unit), + GL_FALSE); + } + + /* Actually want to keep all units less than max active texture + * enabled, right? Fix this for >2 texunits. + */ + /* FIXME: What should happen here if r300UpdateTextureEnv fails? */ + if (unit == 0) + r300UpdateTextureEnv(ctx, unit); + + { + GLuint inputshift = + R200_TEXGEN_0_INPUT_SHIFT + unit * 4; + GLuint tmp = rmesa->TexGenEnabled; + + rmesa->TexGenEnabled &= + ~(R200_TEXGEN_TEXMAT_0_ENABLE << unit); + rmesa->TexGenEnabled &= ~(R200_TEXMAT_0_ENABLE << unit); + rmesa->TexGenEnabled &= + ~(R200_TEXGEN_INPUT_MASK << inputshift); + rmesa->TexGenNeedNormals[unit] = 0; + rmesa->TexGenCompSel &= ~(R200_OUTPUT_TEX_0 << unit); + rmesa->TexGenInputs &= + ~(R200_TEXGEN_INPUT_MASK << inputshift); + + if (tmp != rmesa->TexGenEnabled) { + rmesa->recheck_texgen[unit] = GL_TRUE; + rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } + } + } + #endif +} + +static GLboolean enable_tex_2d(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + + /* Need to load the 2d images associated with this unit. + */ + if (t->format & R200_TXFORMAT_NON_POWER2) { + t->format &= ~R200_TXFORMAT_NON_POWER2; + t->base.dirty_images[0] = ~0; + } + + ASSERT(tObj->Target == GL_TEXTURE_2D || tObj->Target == GL_TEXTURE_1D); + + if (t->base.dirty_images[0]) { + R300_FIREVERTICES(rmesa); + r300SetTexImages(rmesa, tObj); + r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0); + if (!t->base.memBlock) + return GL_FALSE; + } + + return GL_TRUE; +} + +#if ENABLE_HW_3D_TEXTURE +static GLboolean enable_tex_3d(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + + /* Need to load the 3d images associated with this unit. + */ + if (t->format & R200_TXFORMAT_NON_POWER2) { + t->format &= ~R200_TXFORMAT_NON_POWER2; + t->base.dirty_images[0] = ~0; + } + + ASSERT(tObj->Target == GL_TEXTURE_3D); + + /* R100 & R200 do not support mipmaps for 3D textures. + */ + if ((tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR)) { + return GL_FALSE; + } + + if (t->base.dirty_images[0]) { + R300_FIREVERTICES(rmesa); + r300SetTexImages(rmesa, tObj); + r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0); + if (!t->base.memBlock) + return GL_FALSE; + } + + return GL_TRUE; +} +#endif + +static GLboolean enable_tex_cube(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + GLuint face; + + /* Need to load the 2d images associated with this unit. + */ + if (t->format & R200_TXFORMAT_NON_POWER2) { + t->format &= ~R200_TXFORMAT_NON_POWER2; + for (face = 0; face < 6; face++) + t->base.dirty_images[face] = ~0; + } + + ASSERT(tObj->Target == GL_TEXTURE_CUBE_MAP); + + if (t->base.dirty_images[0] || t->base.dirty_images[1] || + t->base.dirty_images[2] || t->base.dirty_images[3] || + t->base.dirty_images[4] || t->base.dirty_images[5]) { + /* flush */ + R300_FIREVERTICES(rmesa); + /* layout memory space, once for all faces */ + r300SetTexImages(rmesa, tObj); + } + + /* upload (per face) */ + for (face = 0; face < 6; face++) { + if (t->base.dirty_images[face]) { + r300UploadTexImages(rmesa, + (r300TexObjPtr) tObj->DriverData, + face); + } + } + + if (!t->base.memBlock) { + /* texmem alloc failed, use s/w fallback */ + return GL_FALSE; + } + + return GL_TRUE; +} + +static GLboolean enable_tex_rect(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + + if (!(t->format & R200_TXFORMAT_NON_POWER2)) { + t->format |= R200_TXFORMAT_NON_POWER2; + t->base.dirty_images[0] = ~0; + } + + ASSERT(tObj->Target == GL_TEXTURE_RECTANGLE_NV); + + if (t->base.dirty_images[0]) { + R300_FIREVERTICES(rmesa); + r300SetTexImages(rmesa, tObj); + r300UploadTexImages(rmesa, (r300TexObjPtr) tObj->DriverData, 0); + if (!t->base.memBlock && !rmesa->prefer_gart_client_texturing) + return GL_FALSE; + } + + return GL_TRUE; +} + +static GLboolean update_tex_common(GLcontext * ctx, int unit) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + r300TexObjPtr t = (r300TexObjPtr) tObj->DriverData; + GLenum format; + + /* Fallback if there's a texture border */ + if (tObj->Image[0][tObj->BaseLevel]->Border > 0) + return GL_FALSE; + + /* Update state if this is a different texture object to last + * time. + */ + if (rmesa->state.texture.unit[unit].texobj != t) { + if (rmesa->state.texture.unit[unit].texobj != NULL) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + rmesa->state.texture.unit[unit].texobj->base.bound &= + ~(1UL << unit); + } + + rmesa->state.texture.unit[unit].texobj = t; + t->base.bound |= (1UL << unit); + t->dirty_state |= 1 << unit; + driUpdateTextureLRU((driTextureObject *) t); /* XXX: should be locked! */ + } + + #if 0 /* do elsewhere ? */ + /* Newly enabled? + */ + if (1 + || !(rmesa->hw.ctx. + cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE << unit))) { + R300_STATECHANGE(rmesa, ctx); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (R200_TEX_0_ENABLE | + R200_TEX_BLEND_0_ENABLE) << + unit; + + R300_STATECHANGE(rmesa, vtx); + rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_VTXFMT_1] |= 4 << (unit * 3); + + rmesa->recheck_texgen[unit] = GL_TRUE; + } + + if (t->dirty_state & (1 << unit)) { + import_tex_obj_state(rmesa, unit, t); + } + + if (rmesa->recheck_texgen[unit]) { + GLboolean fallback = !r300_validate_texgen(ctx, unit); + TCL_FALLBACK(ctx, (RADEON_TCL_FALLBACK_TEXGEN_0 << unit), + fallback); + rmesa->recheck_texgen[unit] = 0; + rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } + + format = tObj->Image[0][tObj->BaseLevel]->Format; + if (rmesa->state.texture.unit[unit].format != format || + rmesa->state.texture.unit[unit].envMode != texUnit->EnvMode) { + rmesa->state.texture.unit[unit].format = format; + rmesa->state.texture.unit[unit].envMode = texUnit->EnvMode; + if (!r300UpdateTextureEnv(ctx, unit)) { + return GL_FALSE; + } + } + #endif + + FALLBACK(&rmesa->radeon, RADEON_FALLBACK_BORDER_MODE, t->border_fallback); + return !t->border_fallback; +} + +static GLboolean r300UpdateTextureUnit(GLcontext * ctx, int unit) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + if (texUnit->_ReallyEnabled & (TEXTURE_RECT_BIT)) { + return (enable_tex_rect(ctx, unit) && + update_tex_common(ctx, unit)); + } else if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) { + return (enable_tex_2d(ctx, unit) && + update_tex_common(ctx, unit)); + } +#if ENABLE_HW_3D_TEXTURE + else if (texUnit->_ReallyEnabled & (TEXTURE_3D_BIT)) { + return (enable_tex_3d(ctx, unit) && + update_tex_common(ctx, unit)); + } +#endif + else if (texUnit->_ReallyEnabled & (TEXTURE_CUBE_BIT)) { + return (enable_tex_cube(ctx, unit) && + update_tex_common(ctx, unit)); + } else if (texUnit->_ReallyEnabled) { + return GL_FALSE; + } else { + disable_tex(ctx, unit); + return GL_TRUE; + } +} + +void r300UpdateTextureState(GLcontext * ctx) +{ + r300ContextPtr rmesa = R300_CONTEXT(ctx); + GLboolean ok; + GLuint dbg; + int i; + + ok = (r300UpdateTextureUnit(ctx, 0) && + r300UpdateTextureUnit(ctx, 1) && + r300UpdateTextureUnit(ctx, 2) && + r300UpdateTextureUnit(ctx, 3) && + r300UpdateTextureUnit(ctx, 4) && + r300UpdateTextureUnit(ctx, 5) && + r300UpdateTextureUnit(ctx, 6) && + r300UpdateTextureUnit(ctx, 7) + ); + + FALLBACK(&rmesa->radeon, RADEON_FALLBACK_TEXTURE, !ok); + + /* This needs correction, or just be done elsewhere + if (rmesa->radeon.TclFallback) + r300ChooseVertexState(ctx); + */ + + #if 0 /* Workaround - disable.. */ + if (GET_CHIP(rmesa->radeon.radeonScreen) == RADEON_CHIP_REAL_R200) { + /* + * T0 hang workaround ------------- + * not needed for r300 derivatives? + */ + if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_ENABLE_MASK) == + R200_TEX_0_ENABLE + && (rmesa->hw.tex[0]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) > + R200_MIN_FILTER_LINEAR) { + + R300_STATECHANGE(rmesa, ctx); + R300_STATECHANGE(rmesa, tex[1]); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_1_ENABLE; + rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &= + ~TEXOBJ_TXFORMAT_MASK; + rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] |= 0x08000000; + } else { + if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_1_ENABLE) + && (rmesa->hw.tex[1]. + cmd[TEX_PP_TXFORMAT] & 0x08000000)) { + R300_STATECHANGE(rmesa, tex[1]); + rmesa->hw.tex[1].cmd[TEX_PP_TXFORMAT] &= + ~0x08000000; + } + } + + /* maybe needs to be done pairwise due to 2 parallel (physical) tex units ? + looks like that's not the case, if 8500/9100 owners don't complain remove this... + for ( i = 0; i < ctx->Const.MaxTextureUnits; i += 2) { + if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & ((R200_TEX_0_ENABLE | + R200_TEX_1_ENABLE ) << i)) == (R200_TEX_0_ENABLE << i)) && + ((rmesa->hw.tex[i].cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK) > + R200_MIN_FILTER_LINEAR)) { + R300_STATECHANGE(rmesa, ctx); + R300_STATECHANGE(rmesa, tex[i+1]); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (R200_TEX_1_ENABLE << i); + rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK; + rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] |= 0x08000000; + } + else { + if ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_1_ENABLE << i)) && + (rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] & 0x08000000)) { + R300_STATECHANGE(rmesa, tex[i+1]); + rmesa->hw.tex[i+1].cmd[TEX_PP_TXFORMAT] &= ~0x08000000; + } + } + } */ + + /* + * Texture cache LRU hang workaround ------------- + * not needed for r300 derivatives? + */ + dbg = 0x0; + + if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_0_ENABLE)) && + ((((rmesa->hw.tex[0]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04) + == 0)) + || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_2_ENABLE) + && + ((((rmesa->hw.tex[2]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & + 0x04) == 0)) + || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_4_ENABLE) + && + ((((rmesa->hw.tex[4]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & + 0x04) == 0))) { + dbg |= 0x02; + } + + if (((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (R200_TEX_1_ENABLE)) && + ((((rmesa->hw.tex[1]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & 0x04) + == 0)) + || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_3_ENABLE) + && + ((((rmesa->hw.tex[3]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & + 0x04) == 0)) + || ((rmesa->hw.ctx.cmd[CTX_PP_CNTL] & R200_TEX_5_ENABLE) + && + ((((rmesa->hw.tex[5]. + cmd[TEX_PP_TXFILTER] & R200_MIN_FILTER_MASK)) & + 0x04) == 0))) { + dbg |= 0x04; + } + + if (dbg != rmesa->hw.tam.cmd[TAM_DEBUG3]) { + R300_STATECHANGE(rmesa, tam); + rmesa->hw.tam.cmd[TAM_DEBUG3] = dbg; + if (0) + printf("TEXCACHE LRU HANG WORKAROUND %x\n", + dbg); + } + } + #endif +} |