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