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