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