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
39static struct ati_fragment_shader DummyShader;
40
41
42void
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 */
65struct 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 */
81void
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
96static void
97new_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
105static void
106new_tex_inst(struct ati_fragment_shader *prog)
107{
108}
109
110static 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
118static char *
119create_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
147static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
148			    "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
149
150static 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
181static 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
210GLuint 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
235void 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
291void 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
328void 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
379void 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
442void 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
514void 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
587static 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
711void 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
720void 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
731void 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
743void 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
751void 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
761void 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
772void 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