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