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