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