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