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