diff options
Diffstat (limited to 'mesalib/src/mesa/main/atifragshader.c')
-rw-r--r-- | mesalib/src/mesa/main/atifragshader.c | 794 |
1 files changed, 794 insertions, 0 deletions
diff --git a/mesalib/src/mesa/main/atifragshader.c b/mesalib/src/mesa/main/atifragshader.c new file mode 100644 index 000000000..550f50b7a --- /dev/null +++ b/mesalib/src/mesa/main/atifragshader.c @@ -0,0 +1,794 @@ +/** + * \file atifragshader.c + * \author David Airlie + * Copyright (C) 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, 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 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 + * DAVID AIRLIE 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/context.h" +#include "main/hash.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/enums.h" +#include "main/mtypes.h" +#include "main/dispatch.h" +#include "main/atifragshader.h" + +#if FEATURE_ATI_fragment_shader + +#define MESA_DEBUG_ATI_FS 0 + +static struct ati_fragment_shader DummyShader; + + +void +_mesa_init_ati_fragment_shader_dispatch(struct _glapi_table *disp) +{ + SET_GenFragmentShadersATI(disp, _mesa_GenFragmentShadersATI); + SET_BindFragmentShaderATI(disp, _mesa_BindFragmentShaderATI); + SET_DeleteFragmentShaderATI(disp, _mesa_DeleteFragmentShaderATI); + SET_BeginFragmentShaderATI(disp, _mesa_BeginFragmentShaderATI); + SET_EndFragmentShaderATI(disp, _mesa_EndFragmentShaderATI); + SET_PassTexCoordATI(disp, _mesa_PassTexCoordATI); + SET_SampleMapATI(disp, _mesa_SampleMapATI); + SET_ColorFragmentOp1ATI(disp, _mesa_ColorFragmentOp1ATI); + SET_ColorFragmentOp2ATI(disp, _mesa_ColorFragmentOp2ATI); + SET_ColorFragmentOp3ATI(disp, _mesa_ColorFragmentOp3ATI); + SET_AlphaFragmentOp1ATI(disp, _mesa_AlphaFragmentOp1ATI); + SET_AlphaFragmentOp2ATI(disp, _mesa_AlphaFragmentOp2ATI); + SET_AlphaFragmentOp3ATI(disp, _mesa_AlphaFragmentOp3ATI); + SET_SetFragmentShaderConstantATI(disp, _mesa_SetFragmentShaderConstantATI); +} + + +/** + * Allocate and initialize a new ATI fragment shader object. + */ +struct ati_fragment_shader * +_mesa_new_ati_fragment_shader(GLcontext *ctx, GLuint id) +{ + struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader); + (void) ctx; + if (s) { + s->Id = id; + s->RefCount = 1; + } + return s; +} + + +/** + * Delete the given ati fragment shader + */ +void +_mesa_delete_ati_fragment_shader(GLcontext *ctx, struct ati_fragment_shader *s) +{ + GLuint i; + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + if (s->Instructions[i]) + free(s->Instructions[i]); + if (s->SetupInst[i]) + free(s->SetupInst[i]); + } + free(s); +} + + + +static void +new_arith_inst(struct ati_fragment_shader *prog) +{ +/* set "default" instruction as not all may get defined. + there is no specified way to express a nop with ati fragment shaders we use + GL_NONE as the op enum and just set some params to 0 - so nothing to do here */ + prog->numArithInstr[prog->cur_pass >> 1]++; +} + +static void +new_tex_inst(struct ati_fragment_shader *prog) +{ +} + +static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype) +{ + if (optype == curProg->last_optype) { + curProg->last_optype = 1; + } +} + +#if MESA_DEBUG_ATI_FS +static char * +create_dst_mod_str(GLuint mod) +{ + static char ret_str[1024]; + + memset(ret_str, 0, 1024); + if (mod & GL_2X_BIT_ATI) + strncat(ret_str, "|2X", 1024); + + if (mod & GL_4X_BIT_ATI) + strncat(ret_str, "|4X", 1024); + + if (mod & GL_8X_BIT_ATI) + strncat(ret_str, "|8X", 1024); + if (mod & GL_HALF_BIT_ATI) + strncat(ret_str, "|HA", 1024); + if (mod & GL_QUARTER_BIT_ATI) + strncat(ret_str, "|QU", 1024); + if (mod & GL_EIGHTH_BIT_ATI) + strncat(ret_str, "|EI", 1024); + + if (mod & GL_SATURATE_BIT_ATI) + strncat(ret_str, "|SAT", 1024); + + if (strlen(ret_str) == 0) + strncat(ret_str, "NONE", 1024); + return ret_str; +} + +static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI", + "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" }; + +static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst, + GLuint dstMask, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + char *op_name; + + op_name = atifs_ops[(arg_count-1)+(optype?3:0)]; + + fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op), + _mesa_lookup_enum_by_nr(dst)); + if (!optype) + fprintf(stderr, ", %d", dstMask); + + fprintf(stderr, ", %s", create_dst_mod_str(dstMod)); + + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1), + _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod); + if (arg_count>1) + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2), + _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod); + if (arg_count>2) + fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3), + _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod); + + fprintf(stderr,")\n"); + +} +#endif + +static int check_arith_arg(struct ati_fragment_shader *curProg, + GLuint optype, GLuint arg, GLuint argRep) +{ + GET_CURRENT_CONTEXT(ctx); + + if (((arg < GL_CON_0_ATI) || (arg > GL_CON_7_ATI)) && + ((arg < GL_REG_0_ATI) || (arg > GL_REG_5_ATI)) && + (arg != GL_ZERO) && (arg != GL_ONE) && + (arg != GL_PRIMARY_COLOR_ARB) && (arg != GL_SECONDARY_INTERPOLATOR_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)"); + return 0; + } + if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) || + ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + return 0; + } + if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) || + ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + return 0; + } + if ((curProg->cur_pass == 1) && + ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) { + curProg->interpinp1 = GL_TRUE; + } + return 1; +} + +GLuint GLAPIENTRY +_mesa_GenFragmentShadersATI(GLuint range) +{ + GLuint first; + GLuint i; + GET_CURRENT_CONTEXT(ctx); + + if (range == 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGenFragmentShadersATI(range)"); + return 0; + } + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glGenFragmentShadersATI(insideShader)"); + return 0; + } + + first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range); + for (i = 0; i < range; i++) { + _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader); + } + + return first; +} + +void GLAPIENTRY +_mesa_BindFragmentShaderATI(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct ati_fragment_shader *newProg; + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragmentShaderATI(insideShader)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + if (curProg->Id == id) { + return; + } + + /* unbind current */ + if (curProg->Id != 0) { + curProg->RefCount--; + if (curProg->RefCount <= 0) { + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + } + } + + /* find new shader */ + if (id == 0) { + newProg = ctx->Shared->DefaultFragmentShader; + } + else { + newProg = (struct ati_fragment_shader *) + _mesa_HashLookup(ctx->Shared->ATIShaders, id); + if (!newProg || newProg == &DummyShader) { + /* allocate a new program now */ + newProg = _mesa_new_ati_fragment_shader(ctx, id); + if (!newProg) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI"); + return; + } + _mesa_HashInsert(ctx->Shared->ATIShaders, id, newProg); + } + + } + + /* do actual bind */ + ctx->ATIFragmentShader.Current = newProg; + + ASSERT(ctx->ATIFragmentShader.Current); + if (newProg) + newProg->RefCount++; + + /*if (ctx->Driver.BindProgram) + ctx->Driver.BindProgram(ctx, target, prog); */ +} + +void GLAPIENTRY +_mesa_DeleteFragmentShaderATI(GLuint id) +{ + GET_CURRENT_CONTEXT(ctx); + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteFragmentShaderATI(insideShader)"); + return; + } + + if (id != 0) { + struct ati_fragment_shader *prog = (struct ati_fragment_shader *) + _mesa_HashLookup(ctx->Shared->ATIShaders, id); + if (prog == &DummyShader) { + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + } + else if (prog) { + if (ctx->ATIFragmentShader.Current && + ctx->ATIFragmentShader.Current->Id == id) { + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_BindFragmentShaderATI(0); + } + } + + /* The ID is immediately available for re-use now */ + _mesa_HashRemove(ctx->Shared->ATIShaders, id); + if (prog) { + prog->RefCount--; + if (prog->RefCount <= 0) { + free(prog); + } + } + } +} + + +void GLAPIENTRY +_mesa_BeginFragmentShaderATI(void) +{ + GLint i; + GET_CURRENT_CONTEXT(ctx); + + if (ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)"); + return; + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + + /* if the shader was already defined free instructions and get new ones + (or, could use the same mem but would need to reinitialize) */ + /* no idea if it's allowed to redefine a shader */ + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + if (ctx->ATIFragmentShader.Current->Instructions[i]) + free(ctx->ATIFragmentShader.Current->Instructions[i]); + if (ctx->ATIFragmentShader.Current->SetupInst[i]) + free(ctx->ATIFragmentShader.Current->SetupInst[i]); + } + + /* malloc the instructions here - not sure if the best place but its + a start */ + for (i = 0; i < MAX_NUM_PASSES_ATI; i++) { + ctx->ATIFragmentShader.Current->Instructions[i] = + (struct atifs_instruction *) + calloc(1, sizeof(struct atifs_instruction) * + (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI)); + ctx->ATIFragmentShader.Current->SetupInst[i] = + (struct atifs_setupinst *) + calloc(1, sizeof(struct atifs_setupinst) * + (MAX_NUM_FRAGMENT_REGISTERS_ATI)); + } + +/* can't rely on calloc for initialization as it's possible to redefine a shader (?) */ + ctx->ATIFragmentShader.Current->LocalConstDef = 0; + ctx->ATIFragmentShader.Current->numArithInstr[0] = 0; + ctx->ATIFragmentShader.Current->numArithInstr[1] = 0; + ctx->ATIFragmentShader.Current->regsAssigned[0] = 0; + ctx->ATIFragmentShader.Current->regsAssigned[1] = 0; + ctx->ATIFragmentShader.Current->NumPasses = 0; + ctx->ATIFragmentShader.Current->cur_pass = 0; + ctx->ATIFragmentShader.Current->last_optype = 0; + ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE; + ctx->ATIFragmentShader.Current->isValid = GL_FALSE; + ctx->ATIFragmentShader.Current->swizzlerq = 0; + ctx->ATIFragmentShader.Compiling = 1; +} + +void GLAPIENTRY +_mesa_EndFragmentShaderATI(void) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; +#if MESA_DEBUG_ATI_FS + GLint i, j; +#endif + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)"); + return; + } + if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)"); + /* according to spec, DON'T return here */ + } + + match_pair_inst(curProg, 0); + ctx->ATIFragmentShader.Compiling = 0; + ctx->ATIFragmentShader.Current->isValid = GL_TRUE; + if ((ctx->ATIFragmentShader.Current->cur_pass == 0) || + (ctx->ATIFragmentShader.Current->cur_pass == 2)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)"); + } + if (ctx->ATIFragmentShader.Current->cur_pass > 1) + ctx->ATIFragmentShader.Current->NumPasses = 2; + else + ctx->ATIFragmentShader.Current->NumPasses = 1; + + ctx->ATIFragmentShader.Current->cur_pass = 0; + +#if MESA_DEBUG_ATI_FS + for (j = 0; j < MAX_NUM_PASSES_ATI; j++) { + for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) { + GLuint op = curProg->SetupInst[j][i].Opcode; + const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0"; + GLuint src = curProg->SetupInst[j][i].src; + GLuint swizzle = curProg->SetupInst[j][i].swizzle; + fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src, + swizzle); + } + for (i = 0; i < curProg->numArithInstr[j]; i++) { + GLuint op0 = curProg->Instructions[j][i].Opcode[0]; + GLuint op1 = curProg->Instructions[j][i].Opcode[1]; + const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0"; + const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0"; + GLuint count0 = curProg->Instructions[j][i].ArgCount[0]; + GLuint count1 = curProg->Instructions[j][i].ArgCount[1]; + fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0, + op1, op1_enum, count1); + } + } +#endif + + if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) { + ctx->ATIFragmentShader.Current->isValid = GL_FALSE; + /* XXX is this the right error? */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEndFragmentShaderATI(driver rejected shader)"); + } +} + +void GLAPIENTRY +_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct atifs_setupinst *curI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)"); + return; + } + + if (curProg->cur_pass == 1) { + match_pair_inst(curProg, 0); + curProg->cur_pass = 2; + } + if ((curProg->cur_pass > 2) || + ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)"); + return; + } + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) || + ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)"); + return; + } + if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) && + ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) || + ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)"); + return; + } + if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)"); + return; + } + if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)"); + return; + } + if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)"); + return; + } + if (coord <= GL_TEXTURE7_ARB) { + GLuint tmp = coord - GL_TEXTURE0_ARB; + if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) && + (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)"); + return; + } else { + curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2)); + } + } + + curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI); + new_tex_inst(curProg); + + /* add the instructions */ + curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI]; + + curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP; + curI->src = coord; + curI->swizzle = swizzle; + +#if MESA_DEBUG_ATI_FS + _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord), + _mesa_lookup_enum_by_nr(swizzle)); +#endif +} + +void GLAPIENTRY +_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + struct atifs_setupinst *curI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)"); + return; + } + + if (curProg->cur_pass == 1) { + match_pair_inst(curProg, 0); + curProg->cur_pass = 2; + } + if ((curProg->cur_pass > 2) || + ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)"); + return; + } + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) || + ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)"); + return; + } + if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) && + ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) || + ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) { + /* is this texture5 or texture7? spec is a bit unclear there */ + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)"); + return; + } + if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)"); + return; + } + if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)"); + return; + } + if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)"); + return; + } + if (interp <= GL_TEXTURE7_ARB) { + GLuint tmp = interp - GL_TEXTURE0_ARB; + if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) && + (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)"); + return; + } else { + curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2)); + } + } + + curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI); + new_tex_inst(curProg); + + /* add the instructions */ + curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI]; + + curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP; + curI->src = interp; + curI->swizzle = swizzle; + +#if MESA_DEBUG_ATI_FS + _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp), + _mesa_lookup_enum_by_nr(swizzle)); +#endif +} + +static void +_mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst, + GLuint dstMask, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + GET_CURRENT_CONTEXT(ctx); + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + GLint ci; + struct atifs_instruction *curI; + GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI; + + if (!ctx->ATIFragmentShader.Compiling) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)"); + return; + } + + if (curProg->cur_pass==0) + curProg->cur_pass=1; + + else if (curProg->cur_pass==2) + curProg->cur_pass=3; + + /* decide whether this is a new instruction or not ... all color instructions are new, + and alpha instructions might also be new if there was no preceding color inst */ + if ((optype == 0) || (curProg->last_optype == optype)) { + if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)"); + return; + } + /* easier to do that here slight side effect invalid instr will still be inserted as nops */ + match_pair_inst(curProg, optype); + new_arith_inst(curProg); + } + curProg->last_optype = optype; + ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1; + + /* add the instructions */ + curI = &curProg->Instructions[curProg->cur_pass >> 1][ci]; + + /* error checking */ + if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)"); + return; + } + if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) && + (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) && + (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) && + (modtemp != GL_EIGHTH_BIT_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp); + return; + } + /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */ + if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) { + _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)"); + return; + } + if (optype == 1) { + if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) || + ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) || + ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) || + ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)"); + return; + } + } + if ((op == GL_DOT4_ATI) && + (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) || + (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)"); + } + + if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) { + return; + } + if (arg2) { + if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) { + return; + } + } + if (arg3) { + if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) { + return; + } + if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) && + (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) && + (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) && + (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)"); + return; + } + } + + /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */ + + curI->Opcode[optype] = op; + curI->SrcReg[optype][0].Index = arg1; + curI->SrcReg[optype][0].argRep = arg1Rep; + curI->SrcReg[optype][0].argMod = arg1Mod; + curI->ArgCount[optype] = arg_count; + + if (arg2) { + curI->SrcReg[optype][1].Index = arg2; + curI->SrcReg[optype][1].argRep = arg2Rep; + curI->SrcReg[optype][1].argMod = arg2Mod; + } + + if (arg3) { + curI->SrcReg[optype][2].Index = arg3; + curI->SrcReg[optype][2].argRep = arg3Rep; + curI->SrcReg[optype][2].argMod = arg3Mod; + } + + curI->DstReg[optype].Index = dst; + curI->DstReg[optype].dstMod = dstMod; + curI->DstReg[optype].dstMask = dstMask; + +#if MESA_DEBUG_ATI_FS + debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod); +#endif + +} + +void GLAPIENTRY +_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, + arg2Mod, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask, + GLuint dstMod, GLuint arg1, GLuint arg1Rep, + GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, + GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, + GLuint arg3Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask, + dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, + arg2Mod, arg3, arg3Rep, arg3Mod); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0, + 0); +} + +void GLAPIENTRY +_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, + GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, + GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, + GLuint arg3Rep, GLuint arg3Mod) +{ + _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod, + arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, + arg3Rep, arg3Mod); +} + +void GLAPIENTRY +_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value) +{ + GLuint dstindex; + GET_CURRENT_CONTEXT(ctx); + + if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) { + /* spec says nothing about what should happen here but we can't just segfault...*/ + _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)"); + return; + } + + dstindex = dst - GL_CON_0_ATI; + if (ctx->ATIFragmentShader.Compiling) { + struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current; + COPY_4V(curProg->Constants[dstindex], value); + curProg->LocalConstDef |= 1 << dstindex; + } + else { + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value); + } +} + +#endif /* FEATURE_ATI_fragment_shader */ |