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