Home | History | Annotate | Download | only in main
      1 /**
      2  * \file atifragshader.c
      3  * \author David Airlie
      4  * Copyright (C) 2004  David Airlie   All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     20  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 #include "main/glheader.h"
     25 #include "main/context.h"
     26 #include "main/hash.h"
     27 #include "main/imports.h"
     28 #include "main/macros.h"
     29 #include "main/mfeatures.h"
     30 #include "main/enums.h"
     31 #include "main/mtypes.h"
     32 #include "main/dispatch.h"
     33 #include "main/atifragshader.h"
     34 
     35 #if FEATURE_ATI_fragment_shader
     36 
     37 #define MESA_DEBUG_ATI_FS 0
     38 
     39 static struct ati_fragment_shader DummyShader;
     40 
     41 
     42 void
     43 _mesa_init_ati_fragment_shader_dispatch(struct _glapi_table *disp)
     44 {
     45    SET_GenFragmentShadersATI(disp, _mesa_GenFragmentShadersATI);
     46    SET_BindFragmentShaderATI(disp, _mesa_BindFragmentShaderATI);
     47    SET_DeleteFragmentShaderATI(disp, _mesa_DeleteFragmentShaderATI);
     48    SET_BeginFragmentShaderATI(disp, _mesa_BeginFragmentShaderATI);
     49    SET_EndFragmentShaderATI(disp, _mesa_EndFragmentShaderATI);
     50    SET_PassTexCoordATI(disp, _mesa_PassTexCoordATI);
     51    SET_SampleMapATI(disp, _mesa_SampleMapATI);
     52    SET_ColorFragmentOp1ATI(disp, _mesa_ColorFragmentOp1ATI);
     53    SET_ColorFragmentOp2ATI(disp, _mesa_ColorFragmentOp2ATI);
     54    SET_ColorFragmentOp3ATI(disp, _mesa_ColorFragmentOp3ATI);
     55    SET_AlphaFragmentOp1ATI(disp, _mesa_AlphaFragmentOp1ATI);
     56    SET_AlphaFragmentOp2ATI(disp, _mesa_AlphaFragmentOp2ATI);
     57    SET_AlphaFragmentOp3ATI(disp, _mesa_AlphaFragmentOp3ATI);
     58    SET_SetFragmentShaderConstantATI(disp, _mesa_SetFragmentShaderConstantATI);
     59 }
     60 
     61 
     62 /**
     63  * Allocate and initialize a new ATI fragment shader object.
     64  */
     65 struct ati_fragment_shader *
     66 _mesa_new_ati_fragment_shader(struct gl_context *ctx, GLuint id)
     67 {
     68    struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader);
     69    (void) ctx;
     70    if (s) {
     71       s->Id = id;
     72       s->RefCount = 1;
     73    }
     74    return s;
     75 }
     76 
     77 
     78 /**
     79  * Delete the given ati fragment shader
     80  */
     81 void
     82 _mesa_delete_ati_fragment_shader(struct gl_context *ctx, struct ati_fragment_shader *s)
     83 {
     84    GLuint i;
     85    for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
     86       if (s->Instructions[i])
     87          free(s->Instructions[i]);
     88       if (s->SetupInst[i])
     89          free(s->SetupInst[i]);
     90    }
     91    free(s);
     92 }
     93 
     94 
     95 
     96 static void
     97 new_arith_inst(struct ati_fragment_shader *prog)
     98 {
     99 /* set "default" instruction as not all may get defined.
    100    there is no specified way to express a nop with ati fragment shaders we use
    101    GL_NONE as the op enum and just set some params to 0 - so nothing to do here */
    102    prog->numArithInstr[prog->cur_pass >> 1]++;
    103 }
    104 
    105 static void
    106 new_tex_inst(struct ati_fragment_shader *prog)
    107 {
    108 }
    109 
    110 static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype)
    111 {
    112    if (optype == curProg->last_optype) {
    113       curProg->last_optype = 1;
    114    }
    115 }
    116 
    117 #if MESA_DEBUG_ATI_FS
    118 static char *
    119 create_dst_mod_str(GLuint mod)
    120 {
    121    static char ret_str[1024];
    122 
    123    memset(ret_str, 0, 1024);
    124    if (mod & GL_2X_BIT_ATI)
    125       strncat(ret_str, "|2X", 1024);
    126 
    127    if (mod & GL_4X_BIT_ATI)
    128       strncat(ret_str, "|4X", 1024);
    129 
    130    if (mod & GL_8X_BIT_ATI)
    131       strncat(ret_str, "|8X", 1024);
    132    if (mod & GL_HALF_BIT_ATI)
    133       strncat(ret_str, "|HA", 1024);
    134    if (mod & GL_QUARTER_BIT_ATI)
    135       strncat(ret_str, "|QU", 1024);
    136    if (mod & GL_EIGHTH_BIT_ATI)
    137       strncat(ret_str, "|EI", 1024);
    138 
    139    if (mod & GL_SATURATE_BIT_ATI)
    140       strncat(ret_str, "|SAT", 1024);
    141 
    142    if (strlen(ret_str) == 0)
    143       strncat(ret_str, "NONE", 1024);
    144    return ret_str;
    145 }
    146 
    147 static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
    148 			    "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
    149 
    150 static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
    151 		     GLuint dstMask, GLuint dstMod, GLuint arg1,
    152 		     GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
    153 		     GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
    154 		     GLuint arg3Rep, GLuint arg3Mod)
    155 {
    156   char *op_name;
    157 
    158   op_name = atifs_ops[(arg_count-1)+(optype?3:0)];
    159 
    160   fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op),
    161 	      _mesa_lookup_enum_by_nr(dst));
    162   if (!optype)
    163     fprintf(stderr, ", %d", dstMask);
    164 
    165   fprintf(stderr, ", %s", create_dst_mod_str(dstMod));
    166 
    167   fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1),
    168 	      _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod);
    169   if (arg_count>1)
    170     fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2),
    171 	      _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod);
    172   if (arg_count>2)
    173     fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3),
    174 	      _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod);
    175 
    176   fprintf(stderr,")\n");
    177 
    178 }
    179 #endif
    180 
    181 static int check_arith_arg(struct ati_fragment_shader *curProg,
    182 			GLuint optype, GLuint arg, GLuint argRep)
    183 {
    184    GET_CURRENT_CONTEXT(ctx);
    185 
    186    if (((arg < GL_CON_0_ATI) || (arg > GL_CON_7_ATI)) &&
    187       ((arg < GL_REG_0_ATI) || (arg > GL_REG_5_ATI)) &&
    188       (arg != GL_ZERO) && (arg != GL_ONE) &&
    189       (arg != GL_PRIMARY_COLOR_ARB) && (arg != GL_SECONDARY_INTERPOLATOR_ATI)) {
    190       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)");
    191       return 0;
    192    }
    193    if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
    194       ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
    195       _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
    196       return 0;
    197    }
    198    if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
    199       ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
    200       _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
    201       return 0;
    202    }
    203    if ((curProg->cur_pass == 1) &&
    204       ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) {
    205       curProg->interpinp1 = GL_TRUE;
    206    }
    207    return 1;
    208 }
    209 
    210 GLuint GLAPIENTRY
    211 _mesa_GenFragmentShadersATI(GLuint range)
    212 {
    213    GLuint first;
    214    GLuint i;
    215    GET_CURRENT_CONTEXT(ctx);
    216 
    217    if (range == 0) {
    218       _mesa_error(ctx, GL_INVALID_VALUE, "glGenFragmentShadersATI(range)");
    219       return 0;
    220    }
    221 
    222    if (ctx->ATIFragmentShader.Compiling) {
    223       _mesa_error(ctx, GL_INVALID_OPERATION, "glGenFragmentShadersATI(insideShader)");
    224       return 0;
    225    }
    226 
    227    first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range);
    228    for (i = 0; i < range; i++) {
    229       _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader);
    230    }
    231 
    232    return first;
    233 }
    234 
    235 void GLAPIENTRY
    236 _mesa_BindFragmentShaderATI(GLuint id)
    237 {
    238    GET_CURRENT_CONTEXT(ctx);
    239    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    240    struct ati_fragment_shader *newProg;
    241 
    242    if (ctx->ATIFragmentShader.Compiling) {
    243       _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragmentShaderATI(insideShader)");
    244       return;
    245    }
    246 
    247    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
    248 
    249    if (curProg->Id == id) {
    250       return;
    251    }
    252 
    253    /* unbind current */
    254    if (curProg->Id != 0) {
    255       curProg->RefCount--;
    256       if (curProg->RefCount <= 0) {
    257 	 _mesa_HashRemove(ctx->Shared->ATIShaders, id);
    258       }
    259    }
    260 
    261    /* find new shader */
    262    if (id == 0) {
    263       newProg = ctx->Shared->DefaultFragmentShader;
    264    }
    265    else {
    266       newProg = (struct ati_fragment_shader *)
    267          _mesa_HashLookup(ctx->Shared->ATIShaders, id);
    268       if (!newProg || newProg == &DummyShader) {
    269 	 /* allocate a new program now */
    270 	 newProg = _mesa_new_ati_fragment_shader(ctx, id);
    271 	 if (!newProg) {
    272 	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI");
    273 	    return;
    274 	 }
    275 	 _mesa_HashInsert(ctx->Shared->ATIShaders, id, newProg);
    276       }
    277 
    278    }
    279 
    280    /* do actual bind */
    281    ctx->ATIFragmentShader.Current = newProg;
    282 
    283    ASSERT(ctx->ATIFragmentShader.Current);
    284    if (newProg)
    285       newProg->RefCount++;
    286 
    287    /*if (ctx->Driver.BindProgram)
    288       ctx->Driver.BindProgram(ctx, target, prog); */
    289 }
    290 
    291 void GLAPIENTRY
    292 _mesa_DeleteFragmentShaderATI(GLuint id)
    293 {
    294    GET_CURRENT_CONTEXT(ctx);
    295 
    296    if (ctx->ATIFragmentShader.Compiling) {
    297       _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteFragmentShaderATI(insideShader)");
    298       return;
    299    }
    300 
    301    if (id != 0) {
    302       struct ati_fragment_shader *prog = (struct ati_fragment_shader *)
    303 	 _mesa_HashLookup(ctx->Shared->ATIShaders, id);
    304       if (prog == &DummyShader) {
    305 	 _mesa_HashRemove(ctx->Shared->ATIShaders, id);
    306       }
    307       else if (prog) {
    308 	 if (ctx->ATIFragmentShader.Current &&
    309 	     ctx->ATIFragmentShader.Current->Id == id) {
    310 	     FLUSH_VERTICES(ctx, _NEW_PROGRAM);
    311 	    _mesa_BindFragmentShaderATI(0);
    312 	 }
    313       }
    314 
    315       /* The ID is immediately available for re-use now */
    316       _mesa_HashRemove(ctx->Shared->ATIShaders, id);
    317       if (prog) {
    318 	 prog->RefCount--;
    319 	 if (prog->RefCount <= 0) {
    320 	    assert(prog != &DummyShader);
    321 	    free(prog);
    322 	 }
    323       }
    324    }
    325 }
    326 
    327 
    328 void GLAPIENTRY
    329 _mesa_BeginFragmentShaderATI(void)
    330 {
    331    GLint i;
    332    GET_CURRENT_CONTEXT(ctx);
    333 
    334    if (ctx->ATIFragmentShader.Compiling) {
    335       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)");
    336       return;
    337    }
    338 
    339    FLUSH_VERTICES(ctx, _NEW_PROGRAM);
    340 
    341    /* if the shader was already defined free instructions and get new ones
    342       (or, could use the same mem but would need to reinitialize) */
    343    /* no idea if it's allowed to redefine a shader */
    344    for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
    345          if (ctx->ATIFragmentShader.Current->Instructions[i])
    346             free(ctx->ATIFragmentShader.Current->Instructions[i]);
    347          if (ctx->ATIFragmentShader.Current->SetupInst[i])
    348             free(ctx->ATIFragmentShader.Current->SetupInst[i]);
    349    }
    350 
    351    /* malloc the instructions here - not sure if the best place but its
    352       a start */
    353    for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
    354       ctx->ATIFragmentShader.Current->Instructions[i] =
    355 	 (struct atifs_instruction *)
    356 	 calloc(1, sizeof(struct atifs_instruction) *
    357 		   (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI));
    358       ctx->ATIFragmentShader.Current->SetupInst[i] =
    359 	 (struct atifs_setupinst *)
    360 	 calloc(1, sizeof(struct atifs_setupinst) *
    361 		   (MAX_NUM_FRAGMENT_REGISTERS_ATI));
    362    }
    363 
    364 /* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
    365    ctx->ATIFragmentShader.Current->LocalConstDef = 0;
    366    ctx->ATIFragmentShader.Current->numArithInstr[0] = 0;
    367    ctx->ATIFragmentShader.Current->numArithInstr[1] = 0;
    368    ctx->ATIFragmentShader.Current->regsAssigned[0] = 0;
    369    ctx->ATIFragmentShader.Current->regsAssigned[1] = 0;
    370    ctx->ATIFragmentShader.Current->NumPasses = 0;
    371    ctx->ATIFragmentShader.Current->cur_pass = 0;
    372    ctx->ATIFragmentShader.Current->last_optype = 0;
    373    ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE;
    374    ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
    375    ctx->ATIFragmentShader.Current->swizzlerq = 0;
    376    ctx->ATIFragmentShader.Compiling = 1;
    377 }
    378 
    379 void GLAPIENTRY
    380 _mesa_EndFragmentShaderATI(void)
    381 {
    382    GET_CURRENT_CONTEXT(ctx);
    383    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    384 #if MESA_DEBUG_ATI_FS
    385    GLint i, j;
    386 #endif
    387 
    388    if (!ctx->ATIFragmentShader.Compiling) {
    389       _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)");
    390       return;
    391    }
    392    if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) {
    393       _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)");
    394    /* according to spec, DON'T return here */
    395    }
    396 
    397    match_pair_inst(curProg, 0);
    398    ctx->ATIFragmentShader.Compiling = 0;
    399    ctx->ATIFragmentShader.Current->isValid = GL_TRUE;
    400    if ((ctx->ATIFragmentShader.Current->cur_pass == 0) ||
    401       (ctx->ATIFragmentShader.Current->cur_pass == 2)) {
    402       _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)");
    403    }
    404    if (ctx->ATIFragmentShader.Current->cur_pass > 1)
    405       ctx->ATIFragmentShader.Current->NumPasses = 2;
    406    else
    407       ctx->ATIFragmentShader.Current->NumPasses = 1;
    408 
    409    ctx->ATIFragmentShader.Current->cur_pass = 0;
    410 
    411 #if MESA_DEBUG_ATI_FS
    412    for (j = 0; j < MAX_NUM_PASSES_ATI; j++) {
    413       for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) {
    414 	 GLuint op = curProg->SetupInst[j][i].Opcode;
    415 	 const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0";
    416 	 GLuint src = curProg->SetupInst[j][i].src;
    417 	 GLuint swizzle = curProg->SetupInst[j][i].swizzle;
    418 	 fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src,
    419 	      swizzle);
    420       }
    421       for (i = 0; i < curProg->numArithInstr[j]; i++) {
    422 	 GLuint op0 = curProg->Instructions[j][i].Opcode[0];
    423 	 GLuint op1 = curProg->Instructions[j][i].Opcode[1];
    424 	 const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0";
    425 	 const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0";
    426 	 GLuint count0 = curProg->Instructions[j][i].ArgCount[0];
    427 	 GLuint count1 = curProg->Instructions[j][i].ArgCount[1];
    428 	 fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0,
    429 	      op1, op1_enum, count1);
    430       }
    431    }
    432 #endif
    433 
    434    if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) {
    435       ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
    436       /* XXX is this the right error? */
    437       _mesa_error(ctx, GL_INVALID_OPERATION,
    438                   "glEndFragmentShaderATI(driver rejected shader)");
    439    }
    440 }
    441 
    442 void GLAPIENTRY
    443 _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
    444 {
    445    GET_CURRENT_CONTEXT(ctx);
    446    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    447    struct atifs_setupinst *curI;
    448 
    449    if (!ctx->ATIFragmentShader.Compiling) {
    450       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)");
    451       return;
    452    }
    453 
    454    if (curProg->cur_pass == 1) {
    455       match_pair_inst(curProg, 0);
    456       curProg->cur_pass = 2;
    457    }
    458    if ((curProg->cur_pass > 2) ||
    459       ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
    460       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)");
    461       return;
    462    }
    463    if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
    464       ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
    465       _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)");
    466       return;
    467    }
    468    if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) &&
    469        ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) ||
    470        ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
    471       _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)");
    472       return;
    473    }
    474    if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) {
    475       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)");
    476       return;
    477    }
    478    if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) {
    479       _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)");
    480       return;
    481    }
    482    if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) {
    483       _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
    484       return;
    485    }
    486    if (coord <= GL_TEXTURE7_ARB) {
    487       GLuint tmp = coord - GL_TEXTURE0_ARB;
    488       if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
    489 	   (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
    490 	 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
    491 	 return;
    492       } else {
    493 	 curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
    494       }
    495    }
    496 
    497    curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
    498    new_tex_inst(curProg);
    499 
    500    /* add the instructions */
    501    curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
    502 
    503    curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP;
    504    curI->src = coord;
    505    curI->swizzle = swizzle;
    506 
    507 #if MESA_DEBUG_ATI_FS
    508    _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
    509 	       _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord),
    510 	       _mesa_lookup_enum_by_nr(swizzle));
    511 #endif
    512 }
    513 
    514 void GLAPIENTRY
    515 _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
    516 {
    517    GET_CURRENT_CONTEXT(ctx);
    518    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    519    struct atifs_setupinst *curI;
    520 
    521    if (!ctx->ATIFragmentShader.Compiling) {
    522       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)");
    523       return;
    524    }
    525 
    526    if (curProg->cur_pass == 1) {
    527       match_pair_inst(curProg, 0);
    528       curProg->cur_pass = 2;
    529    }
    530    if ((curProg->cur_pass > 2) ||
    531       ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
    532       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)");
    533       return;
    534    }
    535    if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
    536       ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
    537       _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)");
    538       return;
    539    }
    540    if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) &&
    541        ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) ||
    542        ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
    543    /* is this texture5 or texture7? spec is a bit unclear there */
    544       _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)");
    545       return;
    546    }
    547    if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) {
    548       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)");
    549       return;
    550    }
    551    if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) {
    552       _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)");
    553       return;
    554    }
    555    if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) {
    556       _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
    557       return;
    558    }
    559    if (interp <= GL_TEXTURE7_ARB) {
    560       GLuint tmp = interp - GL_TEXTURE0_ARB;
    561       if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
    562 	   (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
    563 	 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
    564 	 return;
    565       } else {
    566 	 curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
    567       }
    568    }
    569 
    570    curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
    571    new_tex_inst(curProg);
    572 
    573    /* add the instructions */
    574    curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
    575 
    576    curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP;
    577    curI->src = interp;
    578    curI->swizzle = swizzle;
    579 
    580 #if MESA_DEBUG_ATI_FS
    581    _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
    582 	       _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp),
    583 	       _mesa_lookup_enum_by_nr(swizzle));
    584 #endif
    585 }
    586 
    587 static void
    588 _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
    589 		     GLuint dstMask, GLuint dstMod, GLuint arg1,
    590 		     GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
    591 		     GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
    592 		     GLuint arg3Rep, GLuint arg3Mod)
    593 {
    594    GET_CURRENT_CONTEXT(ctx);
    595    struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    596    GLint ci;
    597    struct atifs_instruction *curI;
    598    GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI;
    599 
    600    if (!ctx->ATIFragmentShader.Compiling) {
    601       _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)");
    602       return;
    603    }
    604 
    605    if (curProg->cur_pass==0)
    606       curProg->cur_pass=1;
    607 
    608    else if (curProg->cur_pass==2)
    609       curProg->cur_pass=3;
    610 
    611    /* decide whether this is a new instruction or not ... all color instructions are new,
    612       and alpha instructions might also be new if there was no preceding color inst */
    613    if ((optype == 0) || (curProg->last_optype == optype)) {
    614       if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) {
    615 	 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)");
    616 	 return;
    617       }
    618       /* easier to do that here slight side effect invalid instr will still be inserted as nops */
    619       match_pair_inst(curProg, optype);
    620       new_arith_inst(curProg);
    621    }
    622    curProg->last_optype = optype;
    623    ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1;
    624 
    625    /* add the instructions */
    626    curI = &curProg->Instructions[curProg->cur_pass >> 1][ci];
    627 
    628    /* error checking */
    629    if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) {
    630       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)");
    631       return;
    632    }
    633    if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) &&
    634       (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) &&
    635       (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) &&
    636       (modtemp != GL_EIGHTH_BIT_ATI)) {
    637       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp);
    638       return;
    639    }
    640    /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */
    641    if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) {
    642       _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)");
    643       return;
    644    }
    645    if (optype == 1) {
    646       if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) ||
    647 	 ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) ||
    648 	 ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) ||
    649 	 ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) {
    650 	 _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)");
    651 	 return;
    652       }
    653    }
    654    if ((op == GL_DOT4_ATI) &&
    655       (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) ||
    656       (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) {
    657       _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
    658    }
    659 
    660    if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) {
    661       return;
    662    }
    663    if (arg2) {
    664       if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) {
    665 	 return;
    666       }
    667    }
    668    if (arg3) {
    669       if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) {
    670 	 return;
    671       }
    672       if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) &&
    673 	  (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) &&
    674 	  (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) &&
    675 	  (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) {
    676 	 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)");
    677 	 return;
    678       }
    679    }
    680 
    681    /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
    682 
    683    curI->Opcode[optype] = op;
    684    curI->SrcReg[optype][0].Index = arg1;
    685    curI->SrcReg[optype][0].argRep = arg1Rep;
    686    curI->SrcReg[optype][0].argMod = arg1Mod;
    687    curI->ArgCount[optype] = arg_count;
    688 
    689    if (arg2) {
    690       curI->SrcReg[optype][1].Index = arg2;
    691       curI->SrcReg[optype][1].argRep = arg2Rep;
    692       curI->SrcReg[optype][1].argMod = arg2Mod;
    693    }
    694 
    695    if (arg3) {
    696       curI->SrcReg[optype][2].Index = arg3;
    697       curI->SrcReg[optype][2].argRep = arg3Rep;
    698       curI->SrcReg[optype][2].argMod = arg3Mod;
    699    }
    700 
    701    curI->DstReg[optype].Index = dst;
    702    curI->DstReg[optype].dstMod = dstMod;
    703    curI->DstReg[optype].dstMask = dstMask;
    704 
    705 #if MESA_DEBUG_ATI_FS
    706    debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
    707 #endif
    708 
    709 }
    710 
    711 void GLAPIENTRY
    712 _mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask,
    713 			  GLuint dstMod, GLuint arg1, GLuint arg1Rep,
    714 			  GLuint arg1Mod)
    715 {
    716    _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask,
    717 			dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
    718 }
    719 
    720 void GLAPIENTRY
    721 _mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask,
    722 			  GLuint dstMod, GLuint arg1, GLuint arg1Rep,
    723 			  GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
    724 			  GLuint arg2Mod)
    725 {
    726    _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask,
    727 			dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
    728 			arg2Mod, 0, 0, 0);
    729 }
    730 
    731 void GLAPIENTRY
    732 _mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask,
    733 			  GLuint dstMod, GLuint arg1, GLuint arg1Rep,
    734 			  GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
    735 			  GLuint arg2Mod, GLuint arg3, GLuint arg3Rep,
    736 			  GLuint arg3Mod)
    737 {
    738    _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask,
    739 			dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
    740 			arg2Mod, arg3, arg3Rep, arg3Mod);
    741 }
    742 
    743 void GLAPIENTRY
    744 _mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
    745 			  GLuint arg1Rep, GLuint arg1Mod)
    746 {
    747    _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod,
    748 			arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
    749 }
    750 
    751 void GLAPIENTRY
    752 _mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
    753 			  GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
    754 			  GLuint arg2Rep, GLuint arg2Mod)
    755 {
    756    _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod,
    757 			arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0,
    758 			0);
    759 }
    760 
    761 void GLAPIENTRY
    762 _mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
    763 			  GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
    764 			  GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
    765 			  GLuint arg3Rep, GLuint arg3Mod)
    766 {
    767    _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod,
    768 			arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3,
    769 			arg3Rep, arg3Mod);
    770 }
    771 
    772 void GLAPIENTRY
    773 _mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value)
    774 {
    775    GLuint dstindex;
    776    GET_CURRENT_CONTEXT(ctx);
    777 
    778    if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) {
    779       /* spec says nothing about what should happen here but we can't just segfault...*/
    780       _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)");
    781       return;
    782    }
    783 
    784    dstindex = dst - GL_CON_0_ATI;
    785    if (ctx->ATIFragmentShader.Compiling) {
    786       struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
    787       COPY_4V(curProg->Constants[dstindex], value);
    788       curProg->LocalConstDef |= 1 << dstindex;
    789    }
    790    else {
    791       FLUSH_VERTICES(ctx, _NEW_PROGRAM);
    792       COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value);
    793    }
    794 }
    795 
    796 #endif /* FEATURE_ATI_fragment_shader */
    797