Merge branch 'llvm-cliptest-viewport'
[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 free(prog);
320 }
321 }
322 }
323 }
324
325
326 void GLAPIENTRY
327 _mesa_BeginFragmentShaderATI(void)
328 {
329 GLint i;
330 GET_CURRENT_CONTEXT(ctx);
331
332 if (ctx->ATIFragmentShader.Compiling) {
333 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)");
334 return;
335 }
336
337 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
338
339 /* if the shader was already defined free instructions and get new ones
340 (or, could use the same mem but would need to reinitialize) */
341 /* no idea if it's allowed to redefine a shader */
342 for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
343 if (ctx->ATIFragmentShader.Current->Instructions[i])
344 free(ctx->ATIFragmentShader.Current->Instructions[i]);
345 if (ctx->ATIFragmentShader.Current->SetupInst[i])
346 free(ctx->ATIFragmentShader.Current->SetupInst[i]);
347 }
348
349 /* malloc the instructions here - not sure if the best place but its
350 a start */
351 for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
352 ctx->ATIFragmentShader.Current->Instructions[i] =
353 (struct atifs_instruction *)
354 calloc(1, sizeof(struct atifs_instruction) *
355 (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI));
356 ctx->ATIFragmentShader.Current->SetupInst[i] =
357 (struct atifs_setupinst *)
358 calloc(1, sizeof(struct atifs_setupinst) *
359 (MAX_NUM_FRAGMENT_REGISTERS_ATI));
360 }
361
362 /* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
363 ctx->ATIFragmentShader.Current->LocalConstDef = 0;
364 ctx->ATIFragmentShader.Current->numArithInstr[0] = 0;
365 ctx->ATIFragmentShader.Current->numArithInstr[1] = 0;
366 ctx->ATIFragmentShader.Current->regsAssigned[0] = 0;
367 ctx->ATIFragmentShader.Current->regsAssigned[1] = 0;
368 ctx->ATIFragmentShader.Current->NumPasses = 0;
369 ctx->ATIFragmentShader.Current->cur_pass = 0;
370 ctx->ATIFragmentShader.Current->last_optype = 0;
371 ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE;
372 ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
373 ctx->ATIFragmentShader.Current->swizzlerq = 0;
374 ctx->ATIFragmentShader.Compiling = 1;
375 }
376
377 void GLAPIENTRY
378 _mesa_EndFragmentShaderATI(void)
379 {
380 GET_CURRENT_CONTEXT(ctx);
381 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
382 #if MESA_DEBUG_ATI_FS
383 GLint i, j;
384 #endif
385
386 if (!ctx->ATIFragmentShader.Compiling) {
387 _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)");
388 return;
389 }
390 if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) {
391 _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)");
392 /* according to spec, DON'T return here */
393 }
394
395 match_pair_inst(curProg, 0);
396 ctx->ATIFragmentShader.Compiling = 0;
397 ctx->ATIFragmentShader.Current->isValid = GL_TRUE;
398 if ((ctx->ATIFragmentShader.Current->cur_pass == 0) ||
399 (ctx->ATIFragmentShader.Current->cur_pass == 2)) {
400 _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)");
401 }
402 if (ctx->ATIFragmentShader.Current->cur_pass > 1)
403 ctx->ATIFragmentShader.Current->NumPasses = 2;
404 else
405 ctx->ATIFragmentShader.Current->NumPasses = 1;
406
407 ctx->ATIFragmentShader.Current->cur_pass = 0;
408
409 #if MESA_DEBUG_ATI_FS
410 for (j = 0; j < MAX_NUM_PASSES_ATI; j++) {
411 for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) {
412 GLuint op = curProg->SetupInst[j][i].Opcode;
413 const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0";
414 GLuint src = curProg->SetupInst[j][i].src;
415 GLuint swizzle = curProg->SetupInst[j][i].swizzle;
416 fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src,
417 swizzle);
418 }
419 for (i = 0; i < curProg->numArithInstr[j]; i++) {
420 GLuint op0 = curProg->Instructions[j][i].Opcode[0];
421 GLuint op1 = curProg->Instructions[j][i].Opcode[1];
422 const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0";
423 const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0";
424 GLuint count0 = curProg->Instructions[j][i].ArgCount[0];
425 GLuint count1 = curProg->Instructions[j][i].ArgCount[1];
426 fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0,
427 op1, op1_enum, count1);
428 }
429 }
430 #endif
431
432 if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) {
433 ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
434 /* XXX is this the right error? */
435 _mesa_error(ctx, GL_INVALID_OPERATION,
436 "glEndFragmentShaderATI(driver rejected shader)");
437 }
438 }
439
440 void GLAPIENTRY
441 _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
442 {
443 GET_CURRENT_CONTEXT(ctx);
444 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
445 struct atifs_setupinst *curI;
446
447 if (!ctx->ATIFragmentShader.Compiling) {
448 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)");
449 return;
450 }
451
452 if (curProg->cur_pass == 1) {
453 match_pair_inst(curProg, 0);
454 curProg->cur_pass = 2;
455 }
456 if ((curProg->cur_pass > 2) ||
457 ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
458 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)");
459 return;
460 }
461 if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
462 ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
463 _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)");
464 return;
465 }
466 if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) &&
467 ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) ||
468 ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
469 _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)");
470 return;
471 }
472 if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) {
473 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)");
474 return;
475 }
476 if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) {
477 _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)");
478 return;
479 }
480 if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) {
481 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
482 return;
483 }
484 if (coord <= GL_TEXTURE7_ARB) {
485 GLuint tmp = coord - GL_TEXTURE0_ARB;
486 if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
487 (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
488 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
489 return;
490 } else {
491 curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
492 }
493 }
494
495 curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
496 new_tex_inst(curProg);
497
498 /* add the instructions */
499 curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
500
501 curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP;
502 curI->src = coord;
503 curI->swizzle = swizzle;
504
505 #if MESA_DEBUG_ATI_FS
506 _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
507 _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord),
508 _mesa_lookup_enum_by_nr(swizzle));
509 #endif
510 }
511
512 void GLAPIENTRY
513 _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
514 {
515 GET_CURRENT_CONTEXT(ctx);
516 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
517 struct atifs_setupinst *curI;
518
519 if (!ctx->ATIFragmentShader.Compiling) {
520 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)");
521 return;
522 }
523
524 if (curProg->cur_pass == 1) {
525 match_pair_inst(curProg, 0);
526 curProg->cur_pass = 2;
527 }
528 if ((curProg->cur_pass > 2) ||
529 ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
530 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)");
531 return;
532 }
533 if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
534 ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
535 _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)");
536 return;
537 }
538 if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) &&
539 ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) ||
540 ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
541 /* is this texture5 or texture7? spec is a bit unclear there */
542 _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)");
543 return;
544 }
545 if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) {
546 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)");
547 return;
548 }
549 if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) {
550 _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)");
551 return;
552 }
553 if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) {
554 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
555 return;
556 }
557 if (interp <= GL_TEXTURE7_ARB) {
558 GLuint tmp = interp - GL_TEXTURE0_ARB;
559 if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
560 (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
561 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
562 return;
563 } else {
564 curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
565 }
566 }
567
568 curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
569 new_tex_inst(curProg);
570
571 /* add the instructions */
572 curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
573
574 curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP;
575 curI->src = interp;
576 curI->swizzle = swizzle;
577
578 #if MESA_DEBUG_ATI_FS
579 _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
580 _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp),
581 _mesa_lookup_enum_by_nr(swizzle));
582 #endif
583 }
584
585 static void
586 _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
587 GLuint dstMask, GLuint dstMod, GLuint arg1,
588 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
589 GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
590 GLuint arg3Rep, GLuint arg3Mod)
591 {
592 GET_CURRENT_CONTEXT(ctx);
593 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
594 GLint ci;
595 struct atifs_instruction *curI;
596 GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI;
597
598 if (!ctx->ATIFragmentShader.Compiling) {
599 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)");
600 return;
601 }
602
603 if (curProg->cur_pass==0)
604 curProg->cur_pass=1;
605
606 else if (curProg->cur_pass==2)
607 curProg->cur_pass=3;
608
609 /* decide whether this is a new instruction or not ... all color instructions are new,
610 and alpha instructions might also be new if there was no preceding color inst */
611 if ((optype == 0) || (curProg->last_optype == optype)) {
612 if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) {
613 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)");
614 return;
615 }
616 /* easier to do that here slight side effect invalid instr will still be inserted as nops */
617 match_pair_inst(curProg, optype);
618 new_arith_inst(curProg);
619 }
620 curProg->last_optype = optype;
621 ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1;
622
623 /* add the instructions */
624 curI = &curProg->Instructions[curProg->cur_pass >> 1][ci];
625
626 /* error checking */
627 if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) {
628 _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)");
629 return;
630 }
631 if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) &&
632 (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) &&
633 (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) &&
634 (modtemp != GL_EIGHTH_BIT_ATI)) {
635 _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp);
636 return;
637 }
638 /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */
639 if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) {
640 _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)");
641 return;
642 }
643 if (optype == 1) {
644 if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) ||
645 ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) ||
646 ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) ||
647 ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) {
648 _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)");
649 return;
650 }
651 }
652 if ((op == GL_DOT4_ATI) &&
653 (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) ||
654 (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) {
655 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
656 }
657
658 if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) {
659 return;
660 }
661 if (arg2) {
662 if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) {
663 return;
664 }
665 }
666 if (arg3) {
667 if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) {
668 return;
669 }
670 if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) &&
671 (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) &&
672 (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) &&
673 (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) {
674 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)");
675 return;
676 }
677 }
678
679 /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
680
681 curI->Opcode[optype] = op;
682 curI->SrcReg[optype][0].Index = arg1;
683 curI->SrcReg[optype][0].argRep = arg1Rep;
684 curI->SrcReg[optype][0].argMod = arg1Mod;
685 curI->ArgCount[optype] = arg_count;
686
687 if (arg2) {
688 curI->SrcReg[optype][1].Index = arg2;
689 curI->SrcReg[optype][1].argRep = arg2Rep;
690 curI->SrcReg[optype][1].argMod = arg2Mod;
691 }
692
693 if (arg3) {
694 curI->SrcReg[optype][2].Index = arg3;
695 curI->SrcReg[optype][2].argRep = arg3Rep;
696 curI->SrcReg[optype][2].argMod = arg3Mod;
697 }
698
699 curI->DstReg[optype].Index = dst;
700 curI->DstReg[optype].dstMod = dstMod;
701 curI->DstReg[optype].dstMask = dstMask;
702
703 #if MESA_DEBUG_ATI_FS
704 debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
705 #endif
706
707 }
708
709 void GLAPIENTRY
710 _mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask,
711 GLuint dstMod, GLuint arg1, GLuint arg1Rep,
712 GLuint arg1Mod)
713 {
714 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask,
715 dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
716 }
717
718 void GLAPIENTRY
719 _mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask,
720 GLuint dstMod, GLuint arg1, GLuint arg1Rep,
721 GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
722 GLuint arg2Mod)
723 {
724 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask,
725 dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
726 arg2Mod, 0, 0, 0);
727 }
728
729 void GLAPIENTRY
730 _mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask,
731 GLuint dstMod, GLuint arg1, GLuint arg1Rep,
732 GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
733 GLuint arg2Mod, GLuint arg3, GLuint arg3Rep,
734 GLuint arg3Mod)
735 {
736 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask,
737 dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
738 arg2Mod, arg3, arg3Rep, arg3Mod);
739 }
740
741 void GLAPIENTRY
742 _mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
743 GLuint arg1Rep, GLuint arg1Mod)
744 {
745 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod,
746 arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
747 }
748
749 void GLAPIENTRY
750 _mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
751 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
752 GLuint arg2Rep, GLuint arg2Mod)
753 {
754 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod,
755 arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0,
756 0);
757 }
758
759 void GLAPIENTRY
760 _mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
761 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
762 GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
763 GLuint arg3Rep, GLuint arg3Mod)
764 {
765 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod,
766 arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3,
767 arg3Rep, arg3Mod);
768 }
769
770 void GLAPIENTRY
771 _mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value)
772 {
773 GLuint dstindex;
774 GET_CURRENT_CONTEXT(ctx);
775
776 if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) {
777 /* spec says nothing about what should happen here but we can't just segfault...*/
778 _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)");
779 return;
780 }
781
782 dstindex = dst - GL_CON_0_ATI;
783 if (ctx->ATIFragmentShader.Compiling) {
784 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
785 COPY_4V(curProg->Constants[dstindex], value);
786 curProg->LocalConstDef |= 1 << dstindex;
787 }
788 else {
789 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
790 COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value);
791 }
792 }
793
794 #endif /* FEATURE_ATI_fragment_shader */