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