Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / atifragshader.c
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 */