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