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