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 "util/imports.h"
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"
35 #define MESA_DEBUG_ATI_FS 0
37 static struct ati_fragment_shader DummyShader
;
41 * Allocate and initialize a new ATI fragment shader object.
43 struct ati_fragment_shader
*
44 _mesa_new_ati_fragment_shader(struct gl_context
*ctx
, GLuint id
)
46 struct ati_fragment_shader
*s
= CALLOC_STRUCT(ati_fragment_shader
);
57 * Delete the given ati fragment shader
60 _mesa_delete_ati_fragment_shader(struct gl_context
*ctx
, struct ati_fragment_shader
*s
)
64 if (s
== &DummyShader
)
67 for (i
= 0; i
< MAX_NUM_PASSES_ATI
; i
++) {
68 free(s
->Instructions
[i
]);
69 free(s
->SetupInst
[i
]);
71 _mesa_reference_program(ctx
, &s
->Program
, NULL
);
76 static void match_pair_inst(struct ati_fragment_shader
*curProg
, GLuint optype
)
78 if (optype
== curProg
->last_optype
) {
79 curProg
->last_optype
= ATI_FRAGMENT_SHADER_ALPHA_OP
;
85 create_dst_mod_str(GLuint mod
)
87 static char ret_str
[1024];
89 memset(ret_str
, 0, 1024);
90 if (mod
& GL_2X_BIT_ATI
)
91 strncat(ret_str
, "|2X", 1024);
93 if (mod
& GL_4X_BIT_ATI
)
94 strncat(ret_str
, "|4X", 1024);
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);
105 if (mod
& GL_SATURATE_BIT_ATI
)
106 strncat(ret_str
, "|SAT", 1024);
108 if (strlen(ret_str
) == 0)
109 strncat(ret_str
, "NONE", 1024);
113 static char *atifs_ops
[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
114 "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
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
)
124 op_name
= atifs_ops
[(arg_count
-1)+(optype
?3:0)];
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
);
131 fprintf(stderr
, ", %s", create_dst_mod_str(dstMod
));
133 fprintf(stderr
, ", %s, %s, %d", _mesa_enum_to_string(arg1
),
134 _mesa_enum_to_string(arg1Rep
), arg1Mod
);
136 fprintf(stderr
, ", %s, %s, %d", _mesa_enum_to_string(arg2
),
137 _mesa_enum_to_string(arg2Rep
), arg2Mod
);
139 fprintf(stderr
, ", %s, %s, %d", _mesa_enum_to_string(arg3
),
140 _mesa_enum_to_string(arg3Rep
), arg3Mod
);
142 fprintf(stderr
,")\n");
148 check_arith_arg(GLuint optype
, GLuint arg
, GLuint argRep
)
150 GET_CURRENT_CONTEXT(ctx
);
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)");
159 /* The ATI_fragment_shader spec says:
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, ...
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)");
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)");
180 check_arg_color(GLubyte pass
, GLuint arg
)
182 if (pass
== 1 && (arg
== GL_PRIMARY_COLOR_ARB
|| arg
== GL_SECONDARY_INTERPOLATOR_ATI
))
188 _mesa_GenFragmentShadersATI(GLuint range
)
192 GET_CURRENT_CONTEXT(ctx
);
195 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenFragmentShadersATI(range)");
199 if (ctx
->ATIFragmentShader
.Compiling
) {
200 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGenFragmentShadersATI(insideShader)");
204 _mesa_HashLockMutex(ctx
->Shared
->ATIShaders
);
206 first
= _mesa_HashFindFreeKeyBlock(ctx
->Shared
->ATIShaders
, range
);
207 for (i
= 0; i
< range
; i
++) {
208 _mesa_HashInsertLocked(ctx
->Shared
->ATIShaders
, first
+ i
, &DummyShader
);
211 _mesa_HashUnlockMutex(ctx
->Shared
->ATIShaders
);
217 _mesa_BindFragmentShaderATI(GLuint id
)
219 GET_CURRENT_CONTEXT(ctx
);
220 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
221 struct ati_fragment_shader
*newProg
;
223 if (ctx
->ATIFragmentShader
.Compiling
) {
224 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBindFragmentShaderATI(insideShader)");
228 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
230 if (curProg
->Id
== id
) {
235 if (curProg
->Id
!= 0) {
237 if (curProg
->RefCount
<= 0) {
238 _mesa_HashRemove(ctx
->Shared
->ATIShaders
, id
);
242 /* find new shader */
244 newProg
= ctx
->Shared
->DefaultFragmentShader
;
247 newProg
= (struct ati_fragment_shader
*)
248 _mesa_HashLookup(ctx
->Shared
->ATIShaders
, id
);
249 if (!newProg
|| newProg
== &DummyShader
) {
250 /* allocate a new program now */
251 newProg
= _mesa_new_ati_fragment_shader(ctx
, id
);
253 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBindFragmentShaderATI");
256 _mesa_HashInsert(ctx
->Shared
->ATIShaders
, id
, newProg
);
262 ctx
->ATIFragmentShader
.Current
= newProg
;
264 assert(ctx
->ATIFragmentShader
.Current
);
270 _mesa_DeleteFragmentShaderATI(GLuint id
)
272 GET_CURRENT_CONTEXT(ctx
);
274 if (ctx
->ATIFragmentShader
.Compiling
) {
275 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDeleteFragmentShaderATI(insideShader)");
280 struct ati_fragment_shader
*prog
= (struct ati_fragment_shader
*)
281 _mesa_HashLookup(ctx
->Shared
->ATIShaders
, id
);
282 if (prog
== &DummyShader
) {
283 _mesa_HashRemove(ctx
->Shared
->ATIShaders
, id
);
286 if (ctx
->ATIFragmentShader
.Current
&&
287 ctx
->ATIFragmentShader
.Current
->Id
== id
) {
288 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
289 _mesa_BindFragmentShaderATI(0);
293 /* The ID is immediately available for re-use now */
294 _mesa_HashRemove(ctx
->Shared
->ATIShaders
, id
);
297 if (prog
->RefCount
<= 0) {
298 _mesa_delete_ati_fragment_shader(ctx
, prog
);
306 _mesa_BeginFragmentShaderATI(void)
309 GET_CURRENT_CONTEXT(ctx
);
311 if (ctx
->ATIFragmentShader
.Compiling
) {
312 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginFragmentShaderATI(insideShader)");
316 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
318 /* if the shader was already defined free instructions and get new ones
319 (or, could use the same mem but would need to reinitialize) */
320 /* no idea if it's allowed to redefine a shader */
321 for (i
= 0; i
< MAX_NUM_PASSES_ATI
; i
++) {
322 free(ctx
->ATIFragmentShader
.Current
->Instructions
[i
]);
323 free(ctx
->ATIFragmentShader
.Current
->SetupInst
[i
]);
326 _mesa_reference_program(ctx
, &ctx
->ATIFragmentShader
.Current
->Program
, NULL
);
328 /* malloc the instructions here - not sure if the best place but its
330 for (i
= 0; i
< MAX_NUM_PASSES_ATI
; i
++) {
331 ctx
->ATIFragmentShader
.Current
->Instructions
[i
] =
332 calloc(sizeof(struct atifs_instruction
),
333 MAX_NUM_INSTRUCTIONS_PER_PASS_ATI
);
334 ctx
->ATIFragmentShader
.Current
->SetupInst
[i
] =
335 calloc(sizeof(struct atifs_setupinst
),
336 MAX_NUM_FRAGMENT_REGISTERS_ATI
);
339 /* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
340 ctx
->ATIFragmentShader
.Current
->LocalConstDef
= 0;
341 ctx
->ATIFragmentShader
.Current
->numArithInstr
[0] = 0;
342 ctx
->ATIFragmentShader
.Current
->numArithInstr
[1] = 0;
343 ctx
->ATIFragmentShader
.Current
->regsAssigned
[0] = 0;
344 ctx
->ATIFragmentShader
.Current
->regsAssigned
[1] = 0;
345 ctx
->ATIFragmentShader
.Current
->NumPasses
= 0;
346 ctx
->ATIFragmentShader
.Current
->cur_pass
= 0;
347 ctx
->ATIFragmentShader
.Current
->last_optype
= 0;
348 ctx
->ATIFragmentShader
.Current
->interpinp1
= GL_FALSE
;
349 ctx
->ATIFragmentShader
.Current
->isValid
= GL_FALSE
;
350 ctx
->ATIFragmentShader
.Current
->swizzlerq
= 0;
351 ctx
->ATIFragmentShader
.Compiling
= 1;
352 #if MESA_DEBUG_ATI_FS
353 _mesa_debug(ctx
, "%s %u\n", __func__
, ctx
->ATIFragmentShader
.Current
->Id
);
358 _mesa_EndFragmentShaderATI(void)
360 GET_CURRENT_CONTEXT(ctx
);
361 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
362 #if MESA_DEBUG_ATI_FS
366 if (!ctx
->ATIFragmentShader
.Compiling
) {
367 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEndFragmentShaderATI(outsideShader)");
370 if (curProg
->interpinp1
&& (ctx
->ATIFragmentShader
.Current
->cur_pass
> 1)) {
371 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEndFragmentShaderATI(interpinfirstpass)");
372 /* according to spec, DON'T return here */
375 match_pair_inst(curProg
, 0);
376 ctx
->ATIFragmentShader
.Compiling
= 0;
377 ctx
->ATIFragmentShader
.Current
->isValid
= GL_TRUE
;
378 if ((ctx
->ATIFragmentShader
.Current
->cur_pass
== 0) ||
379 (ctx
->ATIFragmentShader
.Current
->cur_pass
== 2)) {
380 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glEndFragmentShaderATI(noarithinst)");
382 if (ctx
->ATIFragmentShader
.Current
->cur_pass
> 1)
383 ctx
->ATIFragmentShader
.Current
->NumPasses
= 2;
385 ctx
->ATIFragmentShader
.Current
->NumPasses
= 1;
387 ctx
->ATIFragmentShader
.Current
->cur_pass
= 0;
389 #if MESA_DEBUG_ATI_FS
390 for (j
= 0; j
< MAX_NUM_PASSES_ATI
; j
++) {
391 for (i
= 0; i
< MAX_NUM_FRAGMENT_REGISTERS_ATI
; i
++) {
392 GLuint op
= curProg
->SetupInst
[j
][i
].Opcode
;
393 const char *op_enum
= op
> 5 ? _mesa_enum_to_string(op
) : "0";
394 GLuint src
= curProg
->SetupInst
[j
][i
].src
;
395 GLuint swizzle
= curProg
->SetupInst
[j
][i
].swizzle
;
396 fprintf(stderr
, "%2d %04X %s %d %04X\n", i
, op
, op_enum
, src
,
399 for (i
= 0; i
< curProg
->numArithInstr
[j
]; i
++) {
400 GLuint op0
= curProg
->Instructions
[j
][i
].Opcode
[0];
401 GLuint op1
= curProg
->Instructions
[j
][i
].Opcode
[1];
402 const char *op0_enum
= op0
> 5 ? _mesa_enum_to_string(op0
) : "0";
403 const char *op1_enum
= op1
> 5 ? _mesa_enum_to_string(op1
) : "0";
404 GLuint count0
= curProg
->Instructions
[j
][i
].ArgCount
[0];
405 GLuint count1
= curProg
->Instructions
[j
][i
].ArgCount
[1];
406 fprintf(stderr
, "%2d %04X %s %d %04X %s %d\n", i
, op0
, op0_enum
, count0
,
407 op1
, op1_enum
, count1
);
412 if (ctx
->Driver
.NewATIfs
) {
413 struct gl_program
*prog
= ctx
->Driver
.NewATIfs(ctx
,
414 ctx
->ATIFragmentShader
.Current
);
415 _mesa_reference_program(ctx
, &ctx
->ATIFragmentShader
.Current
->Program
,
417 /* Don't use _mesa_reference_program(), just take ownership */
418 ctx
->ATIFragmentShader
.Current
->Program
= prog
;
421 if (!ctx
->Driver
.ProgramStringNotify(ctx
, GL_FRAGMENT_SHADER_ATI
,
423 ctx
->ATIFragmentShader
.Current
->isValid
= GL_FALSE
;
424 /* XXX is this the right error? */
425 _mesa_error(ctx
, GL_INVALID_OPERATION
,
426 "glEndFragmentShaderATI(driver rejected shader)");
431 _mesa_PassTexCoordATI(GLuint dst
, GLuint coord
, GLenum swizzle
)
433 GET_CURRENT_CONTEXT(ctx
);
434 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
435 struct atifs_setupinst
*curI
;
436 GLubyte new_pass
= curProg
->cur_pass
;
438 if (!ctx
->ATIFragmentShader
.Compiling
) {
439 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(outsideShader)");
443 if (curProg
->cur_pass
== 1)
445 if ((new_pass
> 2) ||
446 ((1 << (dst
- GL_REG_0_ATI
)) & curProg
->regsAssigned
[new_pass
>> 1])) {
447 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoord(pass)");
450 if ((dst
< GL_REG_0_ATI
) || (dst
> GL_REG_5_ATI
) ||
451 ((dst
- GL_REG_0_ATI
) >= ctx
->Const
.MaxTextureUnits
)) {
452 _mesa_error(ctx
, GL_INVALID_ENUM
, "glPassTexCoordATI(dst)");
455 if (((coord
< GL_REG_0_ATI
) || (coord
> GL_REG_5_ATI
)) &&
456 ((coord
< GL_TEXTURE0_ARB
) || (coord
> GL_TEXTURE7_ARB
) ||
457 ((coord
- GL_TEXTURE0_ARB
) >= ctx
->Const
.MaxTextureUnits
))) {
458 _mesa_error(ctx
, GL_INVALID_ENUM
, "glPassTexCoordATI(coord)");
461 if ((new_pass
== 0) && (coord
>= GL_REG_0_ATI
)) {
462 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(coord)");
465 if (!(swizzle
>= GL_SWIZZLE_STR_ATI
) && (swizzle
<= GL_SWIZZLE_STQ_DQ_ATI
)) {
466 _mesa_error(ctx
, GL_INVALID_ENUM
, "glPassTexCoordATI(swizzle)");
469 if ((swizzle
& 1) && (coord
>= GL_REG_0_ATI
)) {
470 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(swizzle)");
473 if (coord
<= GL_TEXTURE7_ARB
) {
474 GLuint tmp
= coord
- GL_TEXTURE0_ARB
;
475 if ((((curProg
->swizzlerq
>> (tmp
* 2)) & 3) != 0) &&
476 (((swizzle
& 1) + 1) != ((curProg
->swizzlerq
>> (tmp
* 2)) & 3))) {
477 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glPassTexCoordATI(swizzle)");
480 curProg
->swizzlerq
|= (((swizzle
& 1) + 1) << (tmp
* 2));
484 if (curProg
->cur_pass
== 1)
485 match_pair_inst(curProg
, 0);
486 curProg
->cur_pass
= new_pass
;
487 curProg
->regsAssigned
[curProg
->cur_pass
>> 1] |= 1 << (dst
- GL_REG_0_ATI
);
489 /* add the instructions */
490 curI
= &curProg
->SetupInst
[curProg
->cur_pass
>> 1][dst
- GL_REG_0_ATI
];
492 curI
->Opcode
= ATI_FRAGMENT_SHADER_PASS_OP
;
494 curI
->swizzle
= swizzle
;
496 #if MESA_DEBUG_ATI_FS
497 _mesa_debug(ctx
, "%s(%s, %s, %s)\n", __func__
,
498 _mesa_enum_to_string(dst
), _mesa_enum_to_string(coord
),
499 _mesa_enum_to_string(swizzle
));
504 _mesa_SampleMapATI(GLuint dst
, GLuint interp
, GLenum swizzle
)
506 GET_CURRENT_CONTEXT(ctx
);
507 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
508 struct atifs_setupinst
*curI
;
509 GLubyte new_pass
= curProg
->cur_pass
;
511 if (!ctx
->ATIFragmentShader
.Compiling
) {
512 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(outsideShader)");
516 if (curProg
->cur_pass
== 1)
518 if ((new_pass
> 2) ||
519 ((1 << (dst
- GL_REG_0_ATI
)) & curProg
->regsAssigned
[new_pass
>> 1])) {
520 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(pass)");
523 if ((dst
< GL_REG_0_ATI
) || (dst
> GL_REG_5_ATI
) ||
524 ((dst
- GL_REG_0_ATI
) >= ctx
->Const
.MaxTextureUnits
)) {
525 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSampleMapATI(dst)");
528 if (((interp
< GL_REG_0_ATI
) || (interp
> GL_REG_5_ATI
)) &&
529 ((interp
< GL_TEXTURE0_ARB
) || (interp
> GL_TEXTURE7_ARB
) ||
530 ((interp
- GL_TEXTURE0_ARB
) >= ctx
->Const
.MaxTextureUnits
))) {
531 /* is this texture5 or texture7? spec is a bit unclear there */
532 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSampleMapATI(interp)");
535 if ((new_pass
== 0) && (interp
>= GL_REG_0_ATI
)) {
536 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(interp)");
539 if (!(swizzle
>= GL_SWIZZLE_STR_ATI
) && (swizzle
<= GL_SWIZZLE_STQ_DQ_ATI
)) {
540 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSampleMapATI(swizzle)");
543 if ((swizzle
& 1) && (interp
>= GL_REG_0_ATI
)) {
544 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(swizzle)");
547 if (interp
<= GL_TEXTURE7_ARB
) {
548 GLuint tmp
= interp
- GL_TEXTURE0_ARB
;
549 if ((((curProg
->swizzlerq
>> (tmp
* 2)) & 3) != 0) &&
550 (((swizzle
& 1) + 1) != ((curProg
->swizzlerq
>> (tmp
* 2)) & 3))) {
551 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glSampleMapATI(swizzle)");
554 curProg
->swizzlerq
|= (((swizzle
& 1) + 1) << (tmp
* 2));
558 if (curProg
->cur_pass
== 1)
559 match_pair_inst(curProg
, 0);
560 curProg
->cur_pass
= new_pass
;
561 curProg
->regsAssigned
[curProg
->cur_pass
>> 1] |= 1 << (dst
- GL_REG_0_ATI
);
563 /* add the instructions */
564 curI
= &curProg
->SetupInst
[curProg
->cur_pass
>> 1][dst
- GL_REG_0_ATI
];
566 curI
->Opcode
= ATI_FRAGMENT_SHADER_SAMPLE_OP
;
568 curI
->swizzle
= swizzle
;
570 #if MESA_DEBUG_ATI_FS
571 _mesa_debug(ctx
, "%s(%s, %s, %s)\n", __func__
,
572 _mesa_enum_to_string(dst
), _mesa_enum_to_string(interp
),
573 _mesa_enum_to_string(swizzle
));
578 _mesa_FragmentOpXATI(GLint optype
, GLuint arg_count
, GLenum op
, GLuint dst
,
579 GLuint dstMask
, GLuint dstMod
, GLuint arg1
,
580 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
581 GLuint arg2Rep
, GLuint arg2Mod
, GLuint arg3
,
582 GLuint arg3Rep
, GLuint arg3Mod
)
584 GET_CURRENT_CONTEXT(ctx
);
585 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
587 struct atifs_instruction
*curI
;
588 GLuint modtemp
= dstMod
& ~GL_SATURATE_BIT_ATI
;
589 GLubyte new_pass
= curProg
->cur_pass
;
590 GLubyte numArithInstr
;
592 if (!ctx
->ATIFragmentShader
.Compiling
) {
593 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(outsideShader)");
597 if (curProg
->cur_pass
== 0)
599 else if (curProg
->cur_pass
== 2)
602 numArithInstr
= curProg
->numArithInstr
[new_pass
>> 1];
604 /* Decide whether this is a new instruction or not. All color instructions
605 * are new, and alpha instructions might also be new if there was no
606 * preceding color inst. This may also be the first inst of the pass
608 if (optype
== ATI_FRAGMENT_SHADER_COLOR_OP
||
609 curProg
->last_optype
== optype
||
610 curProg
->numArithInstr
[new_pass
>> 1] == 0) {
611 if (curProg
->numArithInstr
[new_pass
>> 1] > 7) {
612 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(instrCount)");
617 ci
= numArithInstr
- 1;
618 curI
= &curProg
->Instructions
[new_pass
>> 1][ci
];
621 if ((dst
< GL_REG_0_ATI
) || (dst
> GL_REG_5_ATI
)) {
622 _mesa_error(ctx
, GL_INVALID_ENUM
, "C/AFragmentOpATI(dst)");
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
);
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)");
637 if (optype
== ATI_FRAGMENT_SHADER_ALPHA_OP
) {
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)");
646 /* The ATI_fragment_shader spec says:
648 * The error INVALID_OPERATION is generated by... ColorFragmentOp2ATI
649 * if <op> is DOT4_ATI and <argN> is SECONDARY_INTERPOLATOR_ATI and
650 * <argNRep> is ALPHA or NONE.
652 if (optype
== ATI_FRAGMENT_SHADER_COLOR_OP
&& op
== GL_DOT4_ATI
&&
653 ((arg1
== GL_SECONDARY_INTERPOLATOR_ATI
&& (arg1Rep
== GL_ALPHA
|| arg1Rep
== GL_NONE
)) ||
654 (arg2
== GL_SECONDARY_INTERPOLATOR_ATI
&& (arg2Rep
== GL_ALPHA
|| arg2Rep
== GL_NONE
)))) {
655 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(sec_interpDOT4)");
659 if (!check_arith_arg(optype
, arg1
, arg1Rep
)) {
663 if (!check_arith_arg(optype
, arg2
, arg2Rep
)) {
668 if (!check_arith_arg(optype
, arg3
, arg3Rep
)) {
671 if ((arg1
>= GL_CON_0_ATI
) && (arg1
<= GL_CON_7_ATI
) &&
672 (arg2
>= GL_CON_0_ATI
) && (arg2
<= GL_CON_7_ATI
) &&
673 (arg3
>= GL_CON_0_ATI
) && (arg3
<= GL_CON_7_ATI
) &&
674 (arg1
!= arg2
) && (arg1
!= arg3
) && (arg2
!= arg3
)) {
675 _mesa_error(ctx
, GL_INVALID_OPERATION
, "C/AFragmentOpATI(3Consts)");
680 /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
682 curProg
->interpinp1
|= check_arg_color(new_pass
, arg1
);
684 curProg
->interpinp1
|= check_arg_color(new_pass
, arg2
);
686 curProg
->interpinp1
|= check_arg_color(new_pass
, arg3
);
688 curProg
->numArithInstr
[new_pass
>> 1] = numArithInstr
;
689 curProg
->last_optype
= optype
;
690 curProg
->cur_pass
= new_pass
;
692 curI
->Opcode
[optype
] = op
;
693 curI
->SrcReg
[optype
][0].Index
= arg1
;
694 curI
->SrcReg
[optype
][0].argRep
= arg1Rep
;
695 curI
->SrcReg
[optype
][0].argMod
= arg1Mod
;
696 curI
->ArgCount
[optype
] = arg_count
;
699 curI
->SrcReg
[optype
][1].Index
= arg2
;
700 curI
->SrcReg
[optype
][1].argRep
= arg2Rep
;
701 curI
->SrcReg
[optype
][1].argMod
= arg2Mod
;
705 curI
->SrcReg
[optype
][2].Index
= arg3
;
706 curI
->SrcReg
[optype
][2].argRep
= arg3Rep
;
707 curI
->SrcReg
[optype
][2].argMod
= arg3Mod
;
710 curI
->DstReg
[optype
].Index
= dst
;
711 curI
->DstReg
[optype
].dstMod
= dstMod
;
712 curI
->DstReg
[optype
].dstMask
= dstMask
;
714 #if MESA_DEBUG_ATI_FS
715 debug_op(optype
, arg_count
, op
, dst
, dstMask
, dstMod
, arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
, arg2Mod
, arg3
, arg3Rep
, arg3Mod
);
721 _mesa_ColorFragmentOp1ATI(GLenum op
, GLuint dst
, GLuint dstMask
,
722 GLuint dstMod
, GLuint arg1
, GLuint arg1Rep
,
725 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP
, 1, op
, dst
, dstMask
,
726 dstMod
, arg1
, arg1Rep
, arg1Mod
, 0, 0, 0, 0, 0, 0);
730 _mesa_ColorFragmentOp2ATI(GLenum op
, GLuint dst
, GLuint dstMask
,
731 GLuint dstMod
, GLuint arg1
, GLuint arg1Rep
,
732 GLuint arg1Mod
, GLuint arg2
, GLuint arg2Rep
,
735 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP
, 2, op
, dst
, dstMask
,
736 dstMod
, arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
,
741 _mesa_ColorFragmentOp3ATI(GLenum op
, GLuint dst
, GLuint dstMask
,
742 GLuint dstMod
, GLuint arg1
, GLuint arg1Rep
,
743 GLuint arg1Mod
, GLuint arg2
, GLuint arg2Rep
,
744 GLuint arg2Mod
, GLuint arg3
, GLuint arg3Rep
,
747 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP
, 3, op
, dst
, dstMask
,
748 dstMod
, arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
,
749 arg2Mod
, arg3
, arg3Rep
, arg3Mod
);
753 _mesa_AlphaFragmentOp1ATI(GLenum op
, GLuint dst
, GLuint dstMod
, GLuint arg1
,
754 GLuint arg1Rep
, GLuint arg1Mod
)
756 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP
, 1, op
, dst
, 0, dstMod
,
757 arg1
, arg1Rep
, arg1Mod
, 0, 0, 0, 0, 0, 0);
761 _mesa_AlphaFragmentOp2ATI(GLenum op
, GLuint dst
, GLuint dstMod
, GLuint arg1
,
762 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
763 GLuint arg2Rep
, GLuint arg2Mod
)
765 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP
, 2, op
, dst
, 0, dstMod
,
766 arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
, arg2Mod
, 0, 0,
771 _mesa_AlphaFragmentOp3ATI(GLenum op
, GLuint dst
, GLuint dstMod
, GLuint arg1
,
772 GLuint arg1Rep
, GLuint arg1Mod
, GLuint arg2
,
773 GLuint arg2Rep
, GLuint arg2Mod
, GLuint arg3
,
774 GLuint arg3Rep
, GLuint arg3Mod
)
776 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP
, 3, op
, dst
, 0, dstMod
,
777 arg1
, arg1Rep
, arg1Mod
, arg2
, arg2Rep
, arg2Mod
, arg3
,
782 _mesa_SetFragmentShaderConstantATI(GLuint dst
, const GLfloat
* value
)
785 GET_CURRENT_CONTEXT(ctx
);
787 if ((dst
< GL_CON_0_ATI
) || (dst
> GL_CON_7_ATI
)) {
788 /* spec says nothing about what should happen here but we can't just segfault...*/
789 _mesa_error(ctx
, GL_INVALID_ENUM
, "glSetFragmentShaderConstantATI(dst)");
793 dstindex
= dst
- GL_CON_0_ATI
;
794 if (ctx
->ATIFragmentShader
.Compiling
) {
795 struct ati_fragment_shader
*curProg
= ctx
->ATIFragmentShader
.Current
;
796 COPY_4V(curProg
->Constants
[dstindex
], value
);
797 curProg
->LocalConstDef
|= 1 << dstindex
;
800 FLUSH_VERTICES(ctx
, _NEW_PROGRAM
);
801 COPY_4V(ctx
->ATIFragmentShader
.GlobalConstants
[dstindex
], value
);