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