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