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