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