2 * \file atifragshader.c
4 * Copyright (C) 2004 David Airlie All Rights Reserved.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
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"
35 #if FEATURE_ATI_fragment_shader
37 #define MESA_DEBUG_ATI_FS 0
39 static struct ati_fragment_shader DummyShader
;
43 _mesa_init_ati_fragment_shader_dispatch(struct _glapi_table
*disp
)
45 SET_GenFragmentShadersATI(disp
, _mesa_GenFragmentShadersATI
);
46 SET_BindFragmentShaderATI(disp
, _mesa_BindFragmentShaderATI
);
47 SET_DeleteFragmentShaderATI(disp
, _mesa_DeleteFragmentShaderATI
);
48 SET_BeginFragmentShaderATI(disp
, _mesa_BeginFragmentShaderATI
);
49 SET_EndFragmentShaderATI(disp
, _mesa_EndFragmentShaderATI
);
50 SET_PassTexCoordATI(disp
, _mesa_PassTexCoordATI
);
51 SET_SampleMapATI(disp
, _mesa_SampleMapATI
);
52 SET_ColorFragmentOp1ATI(disp
, _mesa_ColorFragmentOp1ATI
);
53 SET_ColorFragmentOp2ATI(disp
, _mesa_ColorFragmentOp2ATI
);
54 SET_ColorFragmentOp3ATI(disp
, _mesa_ColorFragmentOp3ATI
);
55 SET_AlphaFragmentOp1ATI(disp
, _mesa_AlphaFragmentOp1ATI
);
56 SET_AlphaFragmentOp2ATI(disp
, _mesa_AlphaFragmentOp2ATI
);
57 SET_AlphaFragmentOp3ATI(disp
, _mesa_AlphaFragmentOp3ATI
);
58 SET_SetFragmentShaderConstantATI(disp
, _mesa_SetFragmentShaderConstantATI
);
63 * Allocate and initialize a new ATI fragment shader object.
65 struct ati_fragment_shader
*
66 _mesa_new_ati_fragment_shader(struct gl_context
*ctx
, GLuint id
)
68 struct ati_fragment_shader
*s
= CALLOC_STRUCT(ati_fragment_shader
);
79 * Delete the given ati fragment shader
82 _mesa_delete_ati_fragment_shader(struct gl_context
*ctx
, struct ati_fragment_shader
*s
)
85 for (i
= 0; i
< MAX_NUM_PASSES_ATI
; i
++) {
86 if (s
->Instructions
[i
])
87 free(s
->Instructions
[i
]);
89 free(s
->SetupInst
[i
]);
97 new_arith_inst(struct ati_fragment_shader
*prog
)
99 /* set "default" instruction as not all may get defined.
100 there is no specified way to express a nop with ati fragment shaders we use
101 GL_NONE as the op enum and just set some params to 0 - so nothing to do here */
102 prog
->numArithInstr
[prog
->cur_pass
>> 1]++;
106 new_tex_inst(struct ati_fragment_shader
*prog
)
110 static void match_pair_inst(struct ati_fragment_shader
*curProg
, GLuint optype
)
112 if (optype
== curProg
->last_optype
) {
113 curProg
->last_optype
= 1;
117 #if MESA_DEBUG_ATI_FS
119 create_dst_mod_str(GLuint mod
)
121 static char ret_str
[1024];
123 memset(ret_str
, 0, 1024);
124 if (mod
& GL_2X_BIT_ATI
)
125 strncat(ret_str
, "|2X", 1024);
127 if (mod
& GL_4X_BIT_ATI
)
128 strncat(ret_str
, "|4X", 1024);
130 if (mod
& GL_8X_BIT_ATI
)
131 strncat(ret_str
, "|8X", 1024);
132 if (mod
& GL_HALF_BIT_ATI
)
133 strncat(ret_str
, "|HA", 1024);
134 if (mod
& GL_QUARTER_BIT_ATI
)
135 strncat(ret_str
, "|QU", 1024);
136 if (mod
& GL_EIGHTH_BIT_ATI
)
137 strncat(ret_str
, "|EI", 1024);
139 if (mod
& GL_SATURATE_BIT_ATI
)
140 strncat(ret_str
, "|SAT", 1024);
142 if (strlen(ret_str
) == 0)
143 strncat(ret_str
, "NONE", 1024);
147 static char *atifs_ops
[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
148 "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
150 static void debug_op(GLint optype
, GLuint arg_count
, GLenum op
, GLuint dst
,
151 GLuint dstMask
, GLuint dstMod
, GLuint arg1
,
152 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
153 GLuint arg2Rep
, GLuint arg2Mod
, GLuint arg3
,
154 GLuint arg3Rep
, GLuint arg3Mod
)
158 op_name
= atifs_ops
[(arg_count
-1)+(optype
?3:0)];
160 fprintf(stderr
, "%s(%s, %s", op_name
, _mesa_lookup_enum_by_nr(op
),
161 _mesa_lookup_enum_by_nr(dst
));
163 fprintf(stderr
, ", %d", dstMask
);
165 fprintf(stderr
, ", %s", create_dst_mod_str(dstMod
));
167 fprintf(stderr
, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1
),
168 _mesa_lookup_enum_by_nr(arg1Rep
), arg1Mod
);
170 fprintf(stderr
, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2
),
171 _mesa_lookup_enum_by_nr(arg2Rep
), arg2Mod
);
173 fprintf(stderr
, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3
),
174 _mesa_lookup_enum_by_nr(arg3Rep
), arg3Mod
);
176 fprintf(stderr
,")\n");
181 static int check_arith_arg(struct ati_fragment_shader
*curProg
,
182 GLuint optype
, GLuint arg
, GLuint argRep
)
184 GET_CURRENT_CONTEXT(ctx
);
186 if (((arg
< GL_CON_0_ATI
) || (arg
> GL_CON_7_ATI
)) &&
187 ((arg
< GL_REG_0_ATI
) || (arg
> GL_REG_5_ATI
)) &&
188 (arg
!= GL_ZERO
) && (arg
!= GL_ONE
) &&
189 (arg
!= GL_PRIMARY_COLOR_ARB
) && (arg
!= GL_SECONDARY_INTERPOLATOR_ATI
)) {
190 _mesa_error(ctx
, GL_INVALID_ENUM
, "C/AFragmentOpATI(arg)");
193 if ((arg
== GL_SECONDARY_INTERPOLATOR_ATI
) && (((optype
== 0) && (argRep
== GL_ALPHA
)) ||
194 ((optype
== 1) && ((arg
== GL_ALPHA
) || (argRep
== GL_NONE
))))) {
195 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(sec_interp)");
198 if ((arg
== GL_SECONDARY_INTERPOLATOR_ATI
) && (((optype
== 0) && (argRep
== GL_ALPHA
)) ||
199 ((optype
== 1) && ((arg
== GL_ALPHA
) || (argRep
== GL_NONE
))))) {
200 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(sec_interp)");
203 if ((curProg
->cur_pass
== 1) &&
204 ((arg
== GL_PRIMARY_COLOR_ARB
) || (arg
== GL_SECONDARY_INTERPOLATOR_ATI
))) {
205 curProg
->interpinp1
= GL_TRUE
;
211 _mesa_GenFragmentShadersATI(GLuint range
)
215 GET_CURRENT_CONTEXT(ctx
);
218 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenFragmentShadersATI(range)");
222 if (ctx
->ATIFragmentShader
.Compiling
) {
223 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGenFragmentShadersATI(insideShader)");
227 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->ATIShaders
, range
);
228 for (i
= 0; i
< range
; i
++) {
229 _mesa_HashInsert(ctx
->Shared
->ATIShaders
, first
+ i
, &DummyShader
);
236 _mesa_BindFragmentShaderATI(GLuint id
)
238 GET_CURRENT_CONTEXT(ctx
);
239 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
240 struct ati_fragment_shader
*newProg
;
242 if (ctx
->ATIFragmentShader
.Compiling
) {
243 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBindFragmentShaderATI(insideShader)");
247 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
249 if (curProg
->Id
== id
) {
254 if (curProg
->Id
!= 0) {
256 if (curProg
->RefCount
<= 0) {
257 _mesa_HashRemove(ctx
->Shared
->ATIShaders
, id
);
261 /* find new shader */
263 newProg
= ctx
->Shared
->DefaultFragmentShader
;
266 newProg
= (struct ati_fragment_shader
*)
267 _mesa_HashLookup(ctx
->Shared
->ATIShaders
, id
);
268 if (!newProg
|| newProg
== &DummyShader
) {
269 /* allocate a new program now */
270 newProg
= _mesa_new_ati_fragment_shader(ctx
, id
);
272 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindFragmentShaderATI");
275 _mesa_HashInsert(ctx
->Shared
->ATIShaders
, id
, newProg
);
281 ctx
->ATIFragmentShader
.Current
= newProg
;
283 ASSERT(ctx
->ATIFragmentShader
.Current
);
287 /*if (ctx->Driver.BindProgram)
288 ctx->Driver.BindProgram(ctx, target, prog); */
292 _mesa_DeleteFragmentShaderATI(GLuint id
)
294 GET_CURRENT_CONTEXT(ctx
);
296 if (ctx
->ATIFragmentShader
.Compiling
) {
297 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDeleteFragmentShaderATI(insideShader)");
302 struct ati_fragment_shader
*prog
= (struct ati_fragment_shader
*)
303 _mesa_HashLookup(ctx
->Shared
->ATIShaders
, id
);
304 if (prog
== &DummyShader
) {
305 _mesa_HashRemove(ctx
->Shared
->ATIShaders
, id
);
308 if (ctx
->ATIFragmentShader
.Current
&&
309 ctx
->ATIFragmentShader
.Current
->Id
== id
) {
310 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
311 _mesa_BindFragmentShaderATI(0);
315 /* The ID is immediately available for re-use now */
316 _mesa_HashRemove(ctx
->Shared
->ATIShaders
, id
);
319 if (prog
->RefCount
<= 0) {
320 assert(prog
!= &DummyShader
);
329 _mesa_BeginFragmentShaderATI(void)
332 GET_CURRENT_CONTEXT(ctx
);
334 if (ctx
->ATIFragmentShader
.Compiling
) {
335 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginFragmentShaderATI(insideShader)");
339 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
341 /* if the shader was already defined free instructions and get new ones
342 (or, could use the same mem but would need to reinitialize) */
343 /* no idea if it's allowed to redefine a shader */
344 for (i
= 0; i
< MAX_NUM_PASSES_ATI
; i
++) {
345 if (ctx
->ATIFragmentShader
.Current
->Instructions
[i
])
346 free(ctx
->ATIFragmentShader
.Current
->Instructions
[i
]);
347 if (ctx
->ATIFragmentShader
.Current
->SetupInst
[i
])
348 free(ctx
->ATIFragmentShader
.Current
->SetupInst
[i
]);
351 /* malloc the instructions here - not sure if the best place but its
353 for (i
= 0; i
< MAX_NUM_PASSES_ATI
; i
++) {
354 ctx
->ATIFragmentShader
.Current
->Instructions
[i
] =
355 (struct atifs_instruction
*)
356 calloc(1, sizeof(struct atifs_instruction
) *
357 (MAX_NUM_INSTRUCTIONS_PER_PASS_ATI
));
358 ctx
->ATIFragmentShader
.Current
->SetupInst
[i
] =
359 (struct atifs_setupinst
*)
360 calloc(1, sizeof(struct atifs_setupinst
) *
361 (MAX_NUM_FRAGMENT_REGISTERS_ATI
));
364 /* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
365 ctx
->ATIFragmentShader
.Current
->LocalConstDef
= 0;
366 ctx
->ATIFragmentShader
.Current
->numArithInstr
[0] = 0;
367 ctx
->ATIFragmentShader
.Current
->numArithInstr
[1] = 0;
368 ctx
->ATIFragmentShader
.Current
->regsAssigned
[0] = 0;
369 ctx
->ATIFragmentShader
.Current
->regsAssigned
[1] = 0;
370 ctx
->ATIFragmentShader
.Current
->NumPasses
= 0;
371 ctx
->ATIFragmentShader
.Current
->cur_pass
= 0;
372 ctx
->ATIFragmentShader
.Current
->last_optype
= 0;
373 ctx
->ATIFragmentShader
.Current
->interpinp1
= GL_FALSE
;
374 ctx
->ATIFragmentShader
.Current
->isValid
= GL_FALSE
;
375 ctx
->ATIFragmentShader
.Current
->swizzlerq
= 0;
376 ctx
->ATIFragmentShader
.Compiling
= 1;
380 _mesa_EndFragmentShaderATI(void)
382 GET_CURRENT_CONTEXT(ctx
);
383 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
384 #if MESA_DEBUG_ATI_FS
388 if (!ctx
->ATIFragmentShader
.Compiling
) {
389 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEndFragmentShaderATI(outsideShader)");
392 if (curProg
->interpinp1
&& (ctx
->ATIFragmentShader
.Current
->cur_pass
> 1)) {
393 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEndFragmentShaderATI(interpinfirstpass)");
394 /* according to spec, DON'T return here */
397 match_pair_inst(curProg
, 0);
398 ctx
->ATIFragmentShader
.Compiling
= 0;
399 ctx
->ATIFragmentShader
.Current
->isValid
= GL_TRUE
;
400 if ((ctx
->ATIFragmentShader
.Current
->cur_pass
== 0) ||
401 (ctx
->ATIFragmentShader
.Current
->cur_pass
== 2)) {
402 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEndFragmentShaderATI(noarithinst)");
404 if (ctx
->ATIFragmentShader
.Current
->cur_pass
> 1)
405 ctx
->ATIFragmentShader
.Current
->NumPasses
= 2;
407 ctx
->ATIFragmentShader
.Current
->NumPasses
= 1;
409 ctx
->ATIFragmentShader
.Current
->cur_pass
= 0;
411 #if MESA_DEBUG_ATI_FS
412 for (j
= 0; j
< MAX_NUM_PASSES_ATI
; j
++) {
413 for (i
= 0; i
< MAX_NUM_FRAGMENT_REGISTERS_ATI
; i
++) {
414 GLuint op
= curProg
->SetupInst
[j
][i
].Opcode
;
415 const char *op_enum
= op
> 5 ? _mesa_lookup_enum_by_nr(op
) : "0";
416 GLuint src
= curProg
->SetupInst
[j
][i
].src
;
417 GLuint swizzle
= curProg
->SetupInst
[j
][i
].swizzle
;
418 fprintf(stderr
, "%2d %04X %s %d %04X\n", i
, op
, op_enum
, src
,
421 for (i
= 0; i
< curProg
->numArithInstr
[j
]; i
++) {
422 GLuint op0
= curProg
->Instructions
[j
][i
].Opcode
[0];
423 GLuint op1
= curProg
->Instructions
[j
][i
].Opcode
[1];
424 const char *op0_enum
= op0
> 5 ? _mesa_lookup_enum_by_nr(op0
) : "0";
425 const char *op1_enum
= op1
> 5 ? _mesa_lookup_enum_by_nr(op1
) : "0";
426 GLuint count0
= curProg
->Instructions
[j
][i
].ArgCount
[0];
427 GLuint count1
= curProg
->Instructions
[j
][i
].ArgCount
[1];
428 fprintf(stderr
, "%2d %04X %s %d %04X %s %d\n", i
, op0
, op0_enum
, count0
,
429 op1
, op1_enum
, count1
);
434 if (!ctx
->Driver
.ProgramStringNotify(ctx
, GL_FRAGMENT_SHADER_ATI
, NULL
)) {
435 ctx
->ATIFragmentShader
.Current
->isValid
= GL_FALSE
;
436 /* XXX is this the right error? */
437 _mesa_error(ctx
, GL_INVALID_OPERATION
,
438 "glEndFragmentShaderATI(driver rejected shader)");
443 _mesa_PassTexCoordATI(GLuint dst
, GLuint coord
, GLenum swizzle
)
445 GET_CURRENT_CONTEXT(ctx
);
446 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
447 struct atifs_setupinst
*curI
;
449 if (!ctx
->ATIFragmentShader
.Compiling
) {
450 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(outsideShader)");
454 if (curProg
->cur_pass
== 1) {
455 match_pair_inst(curProg
, 0);
456 curProg
->cur_pass
= 2;
458 if ((curProg
->cur_pass
> 2) ||
459 ((1 << (dst
- GL_REG_0_ATI
)) & curProg
->regsAssigned
[curProg
->cur_pass
>> 1])) {
460 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoord(pass)");
463 if ((dst
< GL_REG_0_ATI
) || (dst
> GL_REG_5_ATI
) ||
464 ((dst
- GL_REG_0_ATI
) >= ctx
->Const
.MaxTextureUnits
)) {
465 _mesa_error(ctx
, GL_INVALID_ENUM
, "glPassTexCoordATI(dst)");
468 if (((coord
< GL_REG_0_ATI
) || (coord
> GL_REG_5_ATI
)) &&
469 ((coord
< GL_TEXTURE0_ARB
) || (coord
> GL_TEXTURE7_ARB
) ||
470 ((coord
- GL_TEXTURE0_ARB
) >= ctx
->Const
.MaxTextureUnits
))) {
471 _mesa_error(ctx
, GL_INVALID_ENUM
, "glPassTexCoordATI(coord)");
474 if ((curProg
->cur_pass
== 0) && (coord
>= GL_REG_0_ATI
)) {
475 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(coord)");
478 if (!(swizzle
>= GL_SWIZZLE_STR_ATI
) && (swizzle
<= GL_SWIZZLE_STQ_DQ_ATI
)) {
479 _mesa_error(ctx
, GL_INVALID_ENUM
, "glPassTexCoordATI(swizzle)");
482 if ((swizzle
& 1) && (coord
>= GL_REG_0_ATI
)) {
483 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(swizzle)");
486 if (coord
<= GL_TEXTURE7_ARB
) {
487 GLuint tmp
= coord
- GL_TEXTURE0_ARB
;
488 if ((((curProg
->swizzlerq
>> (tmp
* 2)) & 3) != 0) &&
489 (((swizzle
& 1) + 1) != ((curProg
->swizzlerq
>> (tmp
* 2)) & 3))) {
490 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(swizzle)");
493 curProg
->swizzlerq
|= (((swizzle
& 1) + 1) << (tmp
* 2));
497 curProg
->regsAssigned
[curProg
->cur_pass
>> 1] |= 1 << (dst
- GL_REG_0_ATI
);
498 new_tex_inst(curProg
);
500 /* add the instructions */
501 curI
= &curProg
->SetupInst
[curProg
->cur_pass
>> 1][dst
- GL_REG_0_ATI
];
503 curI
->Opcode
= ATI_FRAGMENT_SHADER_PASS_OP
;
505 curI
->swizzle
= swizzle
;
507 #if MESA_DEBUG_ATI_FS
508 _mesa_debug(ctx
, "%s(%s, %s, %s)\n", __FUNCTION__
,
509 _mesa_lookup_enum_by_nr(dst
), _mesa_lookup_enum_by_nr(coord
),
510 _mesa_lookup_enum_by_nr(swizzle
));
515 _mesa_SampleMapATI(GLuint dst
, GLuint interp
, GLenum swizzle
)
517 GET_CURRENT_CONTEXT(ctx
);
518 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
519 struct atifs_setupinst
*curI
;
521 if (!ctx
->ATIFragmentShader
.Compiling
) {
522 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(outsideShader)");
526 if (curProg
->cur_pass
== 1) {
527 match_pair_inst(curProg
, 0);
528 curProg
->cur_pass
= 2;
530 if ((curProg
->cur_pass
> 2) ||
531 ((1 << (dst
- GL_REG_0_ATI
)) & curProg
->regsAssigned
[curProg
->cur_pass
>> 1])) {
532 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(pass)");
535 if ((dst
< GL_REG_0_ATI
) || (dst
> GL_REG_5_ATI
) ||
536 ((dst
- GL_REG_0_ATI
) >= ctx
->Const
.MaxTextureUnits
)) {
537 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSampleMapATI(dst)");
540 if (((interp
< GL_REG_0_ATI
) || (interp
> GL_REG_5_ATI
)) &&
541 ((interp
< GL_TEXTURE0_ARB
) || (interp
> GL_TEXTURE7_ARB
) ||
542 ((interp
- GL_TEXTURE0_ARB
) >= ctx
->Const
.MaxTextureUnits
))) {
543 /* is this texture5 or texture7? spec is a bit unclear there */
544 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSampleMapATI(interp)");
547 if ((curProg
->cur_pass
== 0) && (interp
>= GL_REG_0_ATI
)) {
548 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(interp)");
551 if (!(swizzle
>= GL_SWIZZLE_STR_ATI
) && (swizzle
<= GL_SWIZZLE_STQ_DQ_ATI
)) {
552 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSampleMapATI(swizzle)");
555 if ((swizzle
& 1) && (interp
>= GL_REG_0_ATI
)) {
556 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(swizzle)");
559 if (interp
<= GL_TEXTURE7_ARB
) {
560 GLuint tmp
= interp
- GL_TEXTURE0_ARB
;
561 if ((((curProg
->swizzlerq
>> (tmp
* 2)) & 3) != 0) &&
562 (((swizzle
& 1) + 1) != ((curProg
->swizzlerq
>> (tmp
* 2)) & 3))) {
563 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(swizzle)");
566 curProg
->swizzlerq
|= (((swizzle
& 1) + 1) << (tmp
* 2));
570 curProg
->regsAssigned
[curProg
->cur_pass
>> 1] |= 1 << (dst
- GL_REG_0_ATI
);
571 new_tex_inst(curProg
);
573 /* add the instructions */
574 curI
= &curProg
->SetupInst
[curProg
->cur_pass
>> 1][dst
- GL_REG_0_ATI
];
576 curI
->Opcode
= ATI_FRAGMENT_SHADER_SAMPLE_OP
;
578 curI
->swizzle
= swizzle
;
580 #if MESA_DEBUG_ATI_FS
581 _mesa_debug(ctx
, "%s(%s, %s, %s)\n", __FUNCTION__
,
582 _mesa_lookup_enum_by_nr(dst
), _mesa_lookup_enum_by_nr(interp
),
583 _mesa_lookup_enum_by_nr(swizzle
));
588 _mesa_FragmentOpXATI(GLint optype
, GLuint arg_count
, GLenum op
, GLuint dst
,
589 GLuint dstMask
, GLuint dstMod
, GLuint arg1
,
590 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
591 GLuint arg2Rep
, GLuint arg2Mod
, GLuint arg3
,
592 GLuint arg3Rep
, GLuint arg3Mod
)
594 GET_CURRENT_CONTEXT(ctx
);
595 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
597 struct atifs_instruction
*curI
;
598 GLuint modtemp
= dstMod
& ~GL_SATURATE_BIT_ATI
;
600 if (!ctx
->ATIFragmentShader
.Compiling
) {
601 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(outsideShader)");
605 if (curProg
->cur_pass
==0)
608 else if (curProg
->cur_pass
==2)
611 /* decide whether this is a new instruction or not ... all color instructions are new,
612 and alpha instructions might also be new if there was no preceding color inst */
613 if ((optype
== 0) || (curProg
->last_optype
== optype
)) {
614 if (curProg
->numArithInstr
[curProg
->cur_pass
>> 1] > 7) {
615 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(instrCount)");
618 /* easier to do that here slight side effect invalid instr will still be inserted as nops */
619 match_pair_inst(curProg
, optype
);
620 new_arith_inst(curProg
);
622 curProg
->last_optype
= optype
;
623 ci
= curProg
->numArithInstr
[curProg
->cur_pass
>> 1] - 1;
625 /* add the instructions */
626 curI
= &curProg
->Instructions
[curProg
->cur_pass
>> 1][ci
];
629 if ((dst
< GL_REG_0_ATI
) || (dst
> GL_REG_5_ATI
)) {
630 _mesa_error(ctx
, GL_INVALID_ENUM
, "C/AFragmentOpATI(dst)");
633 if ((modtemp
!= GL_NONE
) && (modtemp
!= GL_2X_BIT_ATI
) &&
634 (modtemp
!= GL_4X_BIT_ATI
) && (modtemp
!= GL_8X_BIT_ATI
) &&
635 (modtemp
!= GL_HALF_BIT_ATI
) && !(modtemp
!= GL_QUARTER_BIT_ATI
) &&
636 (modtemp
!= GL_EIGHTH_BIT_ATI
)) {
637 _mesa_error(ctx
, GL_INVALID_ENUM
, "C/AFragmentOpATI(dstMod)%x", modtemp
);
640 /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */
641 if (((op
< GL_ADD_ATI
) || (op
> GL_DOT2_ADD_ATI
)) && !(op
== GL_MOV_ATI
)) {
642 _mesa_error(ctx
, GL_INVALID_ENUM
, "C/AFragmentOpATI(op)");
646 if (((op
== GL_DOT2_ADD_ATI
) && (curI
->Opcode
[0] != GL_DOT2_ADD_ATI
)) ||
647 ((op
== GL_DOT3_ATI
) && (curI
->Opcode
[0] != GL_DOT3_ATI
)) ||
648 ((op
== GL_DOT4_ATI
) && (curI
->Opcode
[0] != GL_DOT4_ATI
)) ||
649 ((op
!= GL_DOT4_ATI
) && (curI
->Opcode
[0] == GL_DOT4_ATI
))) {
650 _mesa_error(ctx
, GL_INVALID_OPERATION
, "AFragmentOpATI(op)");
654 if ((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_interp)");
660 if (!check_arith_arg(curProg
, optype
, arg1
, arg1Rep
)) {
664 if (!check_arith_arg(curProg
, optype
, arg2
, arg2Rep
)) {
669 if (!check_arith_arg(curProg
, optype
, arg3
, arg3Rep
)) {
672 if ((arg1
>= GL_CON_0_ATI
) && (arg1
<= GL_CON_7_ATI
) &&
673 (arg2
>= GL_CON_0_ATI
) && (arg2
<= GL_CON_7_ATI
) &&
674 (arg3
>= GL_CON_0_ATI
) && (arg3
<= GL_CON_7_ATI
) &&
675 (arg1
!= arg2
) && (arg1
!= arg3
) && (arg2
!= arg3
)) {
676 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(3Consts)");
681 /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
683 curI
->Opcode
[optype
] = op
;
684 curI
->SrcReg
[optype
][0].Index
= arg1
;
685 curI
->SrcReg
[optype
][0].argRep
= arg1Rep
;
686 curI
->SrcReg
[optype
][0].argMod
= arg1Mod
;
687 curI
->ArgCount
[optype
] = arg_count
;
690 curI
->SrcReg
[optype
][1].Index
= arg2
;
691 curI
->SrcReg
[optype
][1].argRep
= arg2Rep
;
692 curI
->SrcReg
[optype
][1].argMod
= arg2Mod
;
696 curI
->SrcReg
[optype
][2].Index
= arg3
;
697 curI
->SrcReg
[optype
][2].argRep
= arg3Rep
;
698 curI
->SrcReg
[optype
][2].argMod
= arg3Mod
;
701 curI
->DstReg
[optype
].Index
= dst
;
702 curI
->DstReg
[optype
].dstMod
= dstMod
;
703 curI
->DstReg
[optype
].dstMask
= dstMask
;
705 #if MESA_DEBUG_ATI_FS
706 debug_op(optype
, arg_count
, op
, dst
, dstMask
, dstMod
, arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
, arg2Mod
, arg3
, arg3Rep
, arg3Mod
);
712 _mesa_ColorFragmentOp1ATI(GLenum op
, GLuint dst
, GLuint dstMask
,
713 GLuint dstMod
, GLuint arg1
, GLuint arg1Rep
,
716 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP
, 1, op
, dst
, dstMask
,
717 dstMod
, arg1
, arg1Rep
, arg1Mod
, 0, 0, 0, 0, 0, 0);
721 _mesa_ColorFragmentOp2ATI(GLenum op
, GLuint dst
, GLuint dstMask
,
722 GLuint dstMod
, GLuint arg1
, GLuint arg1Rep
,
723 GLuint arg1Mod
, GLuint arg2
, GLuint arg2Rep
,
726 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP
, 2, op
, dst
, dstMask
,
727 dstMod
, arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
,
732 _mesa_ColorFragmentOp3ATI(GLenum op
, GLuint dst
, GLuint dstMask
,
733 GLuint dstMod
, GLuint arg1
, GLuint arg1Rep
,
734 GLuint arg1Mod
, GLuint arg2
, GLuint arg2Rep
,
735 GLuint arg2Mod
, GLuint arg3
, GLuint arg3Rep
,
738 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP
, 3, op
, dst
, dstMask
,
739 dstMod
, arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
,
740 arg2Mod
, arg3
, arg3Rep
, arg3Mod
);
744 _mesa_AlphaFragmentOp1ATI(GLenum op
, GLuint dst
, GLuint dstMod
, GLuint arg1
,
745 GLuint arg1Rep
, GLuint arg1Mod
)
747 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP
, 1, op
, dst
, 0, dstMod
,
748 arg1
, arg1Rep
, arg1Mod
, 0, 0, 0, 0, 0, 0);
752 _mesa_AlphaFragmentOp2ATI(GLenum op
, GLuint dst
, GLuint dstMod
, GLuint arg1
,
753 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
754 GLuint arg2Rep
, GLuint arg2Mod
)
756 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP
, 2, op
, dst
, 0, dstMod
,
757 arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
, arg2Mod
, 0, 0,
762 _mesa_AlphaFragmentOp3ATI(GLenum op
, GLuint dst
, GLuint dstMod
, GLuint arg1
,
763 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
764 GLuint arg2Rep
, GLuint arg2Mod
, GLuint arg3
,
765 GLuint arg3Rep
, GLuint arg3Mod
)
767 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP
, 3, op
, dst
, 0, dstMod
,
768 arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
, arg2Mod
, arg3
,
773 _mesa_SetFragmentShaderConstantATI(GLuint dst
, const GLfloat
* value
)
776 GET_CURRENT_CONTEXT(ctx
);
778 if ((dst
< GL_CON_0_ATI
) || (dst
> GL_CON_7_ATI
)) {
779 /* spec says nothing about what should happen here but we can't just segfault...*/
780 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSetFragmentShaderConstantATI(dst)");
784 dstindex
= dst
- GL_CON_0_ATI
;
785 if (ctx
->ATIFragmentShader
.Compiling
) {
786 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
787 COPY_4V(curProg
->Constants
[dstindex
], value
);
788 curProg
->LocalConstDef
|= 1 << dstindex
;
791 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
792 COPY_4V(ctx
->ATIFragmentShader
.GlobalConstants
[dstindex
], value
);
796 #endif /* FEATURE_ATI_fragment_shader */