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