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