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