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