/************************************************************************** * * Copyright 2004 David Airlie * 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, 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 DAVID AIRLIE 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. * **************************************************************************/ #include "main/glheader.h" #include "main/atifragshader.h" #include "main/macros.h" #include "main/enums.h" #include "tnl/t_context.h" #include "program/program.h" #include "r200_context.h" #include "r200_ioctl.h" #include "r200_tex.h" #define SET_INST(inst, type) afs_cmd[((inst<<2) + (type<<1) + 1)] #define SET_INST_2(inst, type) afs_cmd[((inst<<2) + (type<<1) + 2)] static void r200SetFragShaderArg( GLuint *afs_cmd, GLuint opnum, GLuint optype, const struct atifragshader_src_register srcReg, GLuint argPos, GLuint *tfactor ) { const GLuint index = srcReg.Index; const GLuint srcmod = srcReg.argMod; const GLuint srcrep = srcReg.argRep; GLuint reg0 = 0; GLuint reg2 = 0; GLuint useOddSrc = 0; switch(srcrep) { case GL_RED: reg2 |= R200_TXC_REPL_RED << (R200_TXC_REPL_ARG_A_SHIFT + (2*argPos)); if (optype) useOddSrc = 1; break; case GL_GREEN: reg2 |= R200_TXC_REPL_GREEN << (R200_TXC_REPL_ARG_A_SHIFT + (2*argPos)); if (optype) useOddSrc = 1; break; case GL_BLUE: if (!optype) reg2 |= R200_TXC_REPL_BLUE << (R200_TXC_REPL_ARG_A_SHIFT + (2*argPos)); else useOddSrc = 1; break; case GL_ALPHA: if (!optype) useOddSrc = 1; break; } if (index >= GL_REG_0_ATI && index <= GL_REG_5_ATI) reg0 |= (((index - GL_REG_0_ATI)*2) + 10 + useOddSrc) << (5*argPos); else if (index >= GL_CON_0_ATI && index <= GL_CON_7_ATI) { if ((*tfactor == 0) || (index == *tfactor)) { reg0 |= (R200_TXC_ARG_A_TFACTOR_COLOR + useOddSrc) << (5*argPos); reg2 |= (index - GL_CON_0_ATI) << R200_TXC_TFACTOR_SEL_SHIFT; *tfactor = index; } else { reg0 |= (R200_TXC_ARG_A_TFACTOR1_COLOR + useOddSrc) << (5*argPos); reg2 |= (index - GL_CON_0_ATI) << R200_TXC_TFACTOR1_SEL_SHIFT; } } else if (index == GL_PRIMARY_COLOR_EXT) { reg0 |= (R200_TXC_ARG_A_DIFFUSE_COLOR + useOddSrc) << (5*argPos); } else if (index == GL_SECONDARY_INTERPOLATOR_ATI) { reg0 |= (R200_TXC_ARG_A_SPECULAR_COLOR + useOddSrc) << (5*argPos); } /* GL_ZERO is a noop, for GL_ONE we set the complement */ else if (index == GL_ONE) { reg0 |= R200_TXC_COMP_ARG_A << (4*argPos); } if (srcmod & GL_COMP_BIT_ATI) reg0 ^= R200_TXC_COMP_ARG_A << (4*argPos); if (srcmod & GL_BIAS_BIT_ATI) reg0 |= R200_TXC_BIAS_ARG_A << (4*argPos); if (srcmod & GL_2X_BIT_ATI) reg0 |= R200_TXC_SCALE_ARG_A << (4*argPos); if (srcmod & GL_NEGATE_BIT_ATI) reg0 ^= R200_TXC_NEG_ARG_A << (4*argPos); SET_INST(opnum, optype) |= reg0; SET_INST_2(opnum, optype) |= reg2; } static GLuint dstmask_table[8] = { R200_TXC_OUTPUT_MASK_RGB, R200_TXC_OUTPUT_MASK_R, R200_TXC_OUTPUT_MASK_G, R200_TXC_OUTPUT_MASK_RG, R200_TXC_OUTPUT_MASK_B, R200_TXC_OUTPUT_MASK_RB, R200_TXC_OUTPUT_MASK_GB, R200_TXC_OUTPUT_MASK_RGB }; static void r200UpdateFSArith( struct gl_context *ctx ) { r200ContextPtr rmesa = R200_CONTEXT(ctx); GLuint *afs_cmd; const struct ati_fragment_shader *shader = ctx->ATIFragmentShader.Current; GLuint pass; R200_STATECHANGE( rmesa, afs[0] ); R200_STATECHANGE( rmesa, afs[1] ); if (shader->NumPasses < 2) { afs_cmd = (GLuint *) rmesa->hw.afs[1].cmd; } else { afs_cmd = (GLuint *) rmesa->hw.afs[0].cmd; } for (pass = 0; pass < shader->NumPasses; pass++) { GLuint opnum = 0; GLuint pc; for (pc = 0; pc < shader->numArithInstr[pass]; pc++) { GLuint optype; struct atifs_instruction *inst = &shader->Instructions[pass][pc]; SET_INST(opnum, 0) = 0; SET_INST_2(opnum, 0) = 0; SET_INST(opnum, 1) = 0; SET_INST_2(opnum, 1) = 0; for (optype = 0; optype < 2; optype++) { GLuint tfactor = 0; if (inst->Opcode[optype]) { switch (inst->Opcode[optype]) { /* these are all MADD in disguise MADD is A * B + C so for GL_ADD use arg B/C and make A complement 0 for GL_SUB use arg B/C, negate C and make A complement 0 for GL_MOV use arg C for GL_MUL use arg A for GL_MAD all good */ case GL_SUB_ATI: /* negate C */ SET_INST(opnum, optype) |= R200_TXC_NEG_ARG_C; /* fallthrough */ case GL_ADD_ATI: r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][0], 1, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][1], 2, &tfactor); /* A = complement 0 */ SET_INST(opnum, optype) |= R200_TXC_COMP_ARG_A; SET_INST(opnum, optype) |= R200_TXC_OP_MADD; break; case GL_MOV_ATI: /* put arg0 in C */ r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][0], 2, &tfactor); SET_INST(opnum, optype) |= R200_TXC_OP_MADD; break; case GL_MAD_ATI: r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][2], 2, &tfactor); /* fallthrough */ case GL_MUL_ATI: r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][1], 1, &tfactor); SET_INST(opnum, optype) |= R200_TXC_OP_MADD; break; case GL_LERP_ATI: /* arg order is not native chip order, swap A and C */ r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][0], 2, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][1], 1, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][2], 0, &tfactor); SET_INST(opnum, optype) |= R200_TXC_OP_LERP; break; case GL_CND_ATI: r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][1], 1, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][2], 2, &tfactor); SET_INST(opnum, optype) |= R200_TXC_OP_CONDITIONAL; break; case GL_CND0_ATI: r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][1], 1, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, optype, inst->SrcReg[optype][2], 2, &tfactor); SET_INST(opnum, optype) |= R200_TXC_OP_CND0; break; /* cannot specify dot ops as alpha ops directly */ case GL_DOT2_ADD_ATI: if (optype) SET_INST_2(opnum, 1) |= R200_TXA_DOT_ALPHA; else { r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][1], 1, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][2], 2, &tfactor); SET_INST(opnum, 0) |= R200_TXC_OP_DOT2_ADD; } break; case GL_DOT3_ATI: if (optype) SET_INST_2(opnum, 1) |= R200_TXA_DOT_ALPHA; else { r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][1], 1, &tfactor); SET_INST(opnum, 0) |= R200_TXC_OP_DOT3; } break; case GL_DOT4_ATI: /* experimental verification: for dot4 setup of alpha args is needed (dstmod is ignored, though, so dot2/dot3 should be safe) the hardware apparently does R1*R2 + G1*G2 + B1*B2 + A3*A4 but the API doesn't allow it */ if (optype) SET_INST_2(opnum, 1) |= R200_TXA_DOT_ALPHA; else { r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, 0, inst->SrcReg[0][1], 1, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, 1, inst->SrcReg[0][0], 0, &tfactor); r200SetFragShaderArg(afs_cmd, opnum, 1, inst->SrcReg[0][1], 1, &tfactor); SET_INST(opnum, optype) |= R200_TXC_OP_DOT4; } break; } } /* destination */ if (inst->DstReg[optype].Index) { GLuint dstreg = inst->DstReg[optype].Index - GL_REG_0_ATI; GLuint dstmask = inst->DstReg[optype].dstMask; GLuint sat = inst->DstReg[optype].dstMod & GL_SATURATE_BIT_ATI; GLuint dstmod = inst->DstReg[optype].dstMod; dstmod &= ~GL_SATURATE_BIT_ATI; SET_INST_2(opnum, optype) |= (dstreg + 1) << R200_TXC_OUTPUT_REG_SHIFT; SET_INST_2(opnum, optype) |= dstmask_table[dstmask]; /* fglrx does clamp the last instructions to 0_1 it seems */ /* this won't necessarily catch the last instruction which writes to reg0 */ if (sat || (pc == (shader->numArithInstr[pass] - 1) && ((pass == 1) || (shader->NumPasses == 1)))) SET_INST_2(opnum, optype) |= R200_TXC_CLAMP_0_1; else /*should we clamp or not? spec is vague, I would suppose yes but fglrx doesn't */ SET_INST_2(opnum, optype) |= R200_TXC_CLAMP_8_8; /* SET_INST_2(opnum, optype) |= R200_TXC_CLAMP_WRAP;*/ switch(dstmod) { case GL_2X_BIT_ATI: SET_INST_2(opnum, optype) |= R200_TXC_SCALE_2X; break; case GL_4X_BIT_ATI: SET_INST_2(opnum, optype) |= R200_TXC_SCALE_4X; break; case GL_8X_BIT_ATI: SET_INST_2(opnum, optype) |= R200_TXC_SCALE_8X; break; case GL_HALF_BIT_ATI: SET_INST_2(opnum, optype) |= R200_TXC_SCALE_INV2; break; case GL_QUARTER_BIT_ATI: SET_INST_2(opnum, optype) |= R200_TXC_SCALE_INV4; break; case GL_EIGHTH_BIT_ATI: SET_INST_2(opnum, optype) |= R200_TXC_SCALE_INV8; break; default: break; } } } /* fprintf(stderr, "pass %d nr %d inst 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", pass, opnum, SET_INST(opnum, 0), SET_INST_2(opnum, 0), SET_INST(opnum, 1), SET_INST_2(opnum, 1));*/ opnum++; } afs_cmd = (GLuint *) rmesa->hw.afs[1].cmd; } rmesa->afs_loaded = ctx->ATIFragmentShader.Current; } static void r200UpdateFSRouting( struct gl_context *ctx ) { r200ContextPtr rmesa = R200_CONTEXT(ctx); const struct ati_fragment_shader *shader = ctx->ATIFragmentShader.Current; GLuint reg; R200_STATECHANGE( rmesa, ctx ); R200_STATECHANGE( rmesa, cst ); for (reg = 0; reg < R200_MAX_TEXTURE_UNITS; reg++) { if (shader->swizzlerq & (1 << (2 * reg))) /* r coord */ set_re_cntl_d3d( ctx, reg, 1); /* q coord */ else set_re_cntl_d3d( ctx, reg, 0); } rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~(R200_MULTI_PASS_ENABLE | R200_TEX_BLEND_ENABLE_MASK | R200_TEX_ENABLE_MASK); rmesa->hw.cst.cmd[CST_PP_CNTL_X] &= ~(R200_PPX_PFS_INST_ENABLE_MASK | R200_PPX_TEX_ENABLE_MASK | R200_PPX_OUTPUT_REG_MASK); /* first pass registers use slots 8 - 15 but single pass shaders use slots 0 - 7 */ if (shader->NumPasses < 2) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= shader->numArithInstr[0] == 8 ? 0xff << (R200_TEX_BLEND_0_ENABLE_SHIFT - 1) : (0xff >> (8 - shader->numArithInstr[0])) << R200_TEX_BLEND_0_ENABLE_SHIFT; } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_MULTI_PASS_ENABLE; rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= shader->numArithInstr[1] == 8 ? 0xff << (R200_TEX_BLEND_0_ENABLE_SHIFT - 1) : (0xff >> (8 - shader->numArithInstr[1])) << R200_TEX_BLEND_0_ENABLE_SHIFT; rmesa->hw.cst.cmd[CST_PP_CNTL_X] |= (0xff >> (8 - shader->numArithInstr[0])) << R200_PPX_FPS_INST0_ENABLE_SHIFT; } if (shader->NumPasses < 2) { for (reg = 0; reg < R200_MAX_TEXTURE_UNITS; reg++) { struct gl_texture_object *texObj = ctx->Texture.Unit[reg]._Current; R200_STATECHANGE( rmesa, tex[reg] ); rmesa->hw.tex[reg].cmd[TEX_PP_TXMULTI_CTL] = 0; if (shader->SetupInst[0][reg].Opcode) { GLuint txformat = rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT] & ~(R200_TXFORMAT_ST_ROUTE_MASK | R200_TXFORMAT_LOOKUP_DISABLE); GLuint txformat_x = rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT_X] & ~R200_TEXCOORD_MASK; txformat |= (shader->SetupInst[0][reg].src - GL_TEXTURE0_ARB) << R200_TXFORMAT_ST_ROUTE_SHIFT; /* fix up texcoords for proj/non-proj 2d (3d and cube are not defined when using projection so don't have to worry there). When passing coords, need R200_TEXCOORD_VOLUME, otherwise loose a coord */ /* FIXME: someone might rely on default tex coords r/q, which we unfortunately don't provide (we have the same problem without shaders) */ if (shader->SetupInst[0][reg].Opcode == ATI_FRAGMENT_SHADER_PASS_OP) { txformat |= R200_TXFORMAT_LOOKUP_DISABLE; if (shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STR_ATI || shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STQ_ATI) { txformat_x |= R200_TEXCOORD_VOLUME; } else { txformat_x |= R200_TEXCOORD_PROJ; } rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_0_ENABLE << reg; } else if (texObj && texObj->Target == GL_TEXTURE_3D) { txformat_x |= R200_TEXCOORD_VOLUME; } else if (texObj && texObj->Target == GL_TEXTURE_CUBE_MAP) { txformat_x |= R200_TEXCOORD_CUBIC_ENV; } else if (shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STR_ATI || shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STQ_ATI) { txformat_x |= R200_TEXCOORD_NONPROJ; } else { txformat_x |= R200_TEXCOORD_PROJ; } rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT] = txformat; rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT_X] = txformat_x; /* enabling texturing when unit isn't correctly configured may not be safe */ if (texObj) rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_0_ENABLE << reg; } } } else { /* setup 1st pass */ for (reg = 0; reg < R200_MAX_TEXTURE_UNITS; reg++) { struct gl_texture_object *texObj = ctx->Texture.Unit[reg]._Current; R200_STATECHANGE( rmesa, tex[reg] ); GLuint txformat_multi = 0; if (shader->SetupInst[0][reg].Opcode) { txformat_multi |= (shader->SetupInst[0][reg].src - GL_TEXTURE0_ARB) << R200_PASS1_ST_ROUTE_SHIFT; if (shader->SetupInst[0][reg].Opcode == ATI_FRAGMENT_SHADER_PASS_OP) { txformat_multi |= R200_PASS1_TXFORMAT_LOOKUP_DISABLE; if (shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STR_ATI || shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STQ_ATI) { txformat_multi |= R200_PASS1_TEXCOORD_VOLUME; } else { txformat_multi |= R200_PASS1_TEXCOORD_PROJ; } rmesa->hw.cst.cmd[CST_PP_CNTL_X] |= R200_PPX_TEX_0_ENABLE << reg; } else if (texObj && texObj->Target == GL_TEXTURE_3D) { txformat_multi |= R200_PASS1_TEXCOORD_VOLUME; } else if (texObj && texObj->Target == GL_TEXTURE_CUBE_MAP) { txformat_multi |= R200_PASS1_TEXCOORD_CUBIC_ENV; } else if (shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STR_ATI || shader->SetupInst[0][reg].swizzle == GL_SWIZZLE_STQ_ATI) { txformat_multi |= R200_PASS1_TEXCOORD_NONPROJ; } else { txformat_multi |= R200_PASS1_TEXCOORD_PROJ; } if (texObj) rmesa->hw.cst.cmd[CST_PP_CNTL_X] |= R200_PPX_TEX_0_ENABLE << reg; } rmesa->hw.tex[reg].cmd[TEX_PP_TXMULTI_CTL] = txformat_multi; } /* setup 2nd pass */ for (reg=0; reg < R200_MAX_TEXTURE_UNITS; reg++) { struct gl_texture_object *texObj = ctx->Texture.Unit[reg]._Current; if (shader->SetupInst[1][reg].Opcode) { GLuint coord = shader->SetupInst[1][reg].src; GLuint txformat = rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT] & ~(R200_TXFORMAT_ST_ROUTE_MASK | R200_TXFORMAT_LOOKUP_DISABLE); GLuint txformat_x = rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT_X] & ~R200_TEXCOORD_MASK; R200_STATECHANGE( rmesa, tex[reg] ); if (shader->SetupInst[1][reg].Opcode == ATI_FRAGMENT_SHADER_PASS_OP) { txformat |= R200_TXFORMAT_LOOKUP_DISABLE; txformat_x |= R200_TEXCOORD_VOLUME; if (shader->SetupInst[1][reg].swizzle == GL_SWIZZLE_STR_ATI || shader->SetupInst[1][reg].swizzle == GL_SWIZZLE_STQ_ATI) { txformat_x |= R200_TEXCOORD_VOLUME; } else { txformat_x |= R200_TEXCOORD_PROJ; } rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_0_ENABLE << reg; } else if (texObj && texObj->Target == GL_TEXTURE_3D) { txformat_x |= R200_TEXCOORD_VOLUME; } else if (texObj && texObj->Target == GL_TEXTURE_CUBE_MAP) { txformat_x |= R200_TEXCOORD_CUBIC_ENV; } else if (shader->SetupInst[1][reg].swizzle == GL_SWIZZLE_STR_ATI || shader->SetupInst[1][reg].swizzle == GL_SWIZZLE_STQ_ATI) { txformat_x |= R200_TEXCOORD_NONPROJ; } else { txformat_x |= R200_TEXCOORD_PROJ; } if (coord >= GL_REG_0_ATI) { GLuint txformat_multi = rmesa->hw.tex[reg].cmd[TEX_PP_TXMULTI_CTL]; txformat_multi |= (coord - GL_REG_0_ATI + 2) << R200_PASS2_COORDS_REG_SHIFT; rmesa->hw.tex[reg].cmd[TEX_PP_TXMULTI_CTL] = txformat_multi; rmesa->hw.cst.cmd[CST_PP_CNTL_X] |= 1 << (R200_PPX_OUTPUT_REG_0_SHIFT + coord - GL_REG_0_ATI); } else { txformat |= (coord - GL_TEXTURE0_ARB) << R200_TXFORMAT_ST_ROUTE_SHIFT; } rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT_X] = txformat_x; rmesa->hw.tex[reg].cmd[TEX_PP_TXFORMAT] = txformat; if (texObj) rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= R200_TEX_0_ENABLE << reg; } } } } static void r200UpdateFSConstants( struct gl_context *ctx ) { r200ContextPtr rmesa = R200_CONTEXT(ctx); const struct ati_fragment_shader *shader = ctx->ATIFragmentShader.Current; GLuint i; /* update constants */ R200_STATECHANGE(rmesa, atf); for (i = 0; i < 8; i++) { GLubyte con_byte[4]; if ((shader->LocalConstDef >> i) & 1) { CLAMPED_FLOAT_TO_UBYTE(con_byte[0], shader->Constants[i][0]); CLAMPED_FLOAT_TO_UBYTE(con_byte[1], shader->Constants[i][1]); CLAMPED_FLOAT_TO_UBYTE(con_byte[2], shader->Constants[i][2]); CLAMPED_FLOAT_TO_UBYTE(con_byte[3], shader->Constants[i][3]); } else { CLAMPED_FLOAT_TO_UBYTE(con_byte[0], ctx->ATIFragmentShader.GlobalConstants[i][0]); CLAMPED_FLOAT_TO_UBYTE(con_byte[1], ctx->ATIFragmentShader.GlobalConstants[i][1]); CLAMPED_FLOAT_TO_UBYTE(con_byte[2], ctx->ATIFragmentShader.GlobalConstants[i][2]); CLAMPED_FLOAT_TO_UBYTE(con_byte[3], ctx->ATIFragmentShader.GlobalConstants[i][3]); } rmesa->hw.atf.cmd[ATF_TFACTOR_0 + i] = radeonPackColor ( 4, con_byte[0], con_byte[1], con_byte[2], con_byte[3] ); } } /* update routing, constants and arithmetic * constants need to be updated always (globals can change, no separate notification) * routing needs to be updated always too (non-shader code will overwrite state, plus * some of the routing depends on what sort of texture is bound) * for both of them, we need to update anyway because of disabling/enabling ati_fs which * we'd need to track otherwise * arithmetic is only updated if current shader changes (and probably the data should be * stored in some DriverData object attached to the mesa atifs object, i.e. binding a * shader wouldn't force us to "recompile" the shader). */ void r200UpdateFragmentShader( struct gl_context *ctx ) { r200ContextPtr rmesa = R200_CONTEXT(ctx); r200UpdateFSConstants( ctx ); r200UpdateFSRouting( ctx ); if (rmesa->afs_loaded != ctx->ATIFragmentShader.Current) r200UpdateFSArith( ctx ); }