blob: 6676d3cfa9e2195de60d70e4b4115c331a007bc8 [file] [log] [blame]
Keith Whitwell15e75e02005-04-29 15:11:39 +00001/**************************************************************************
2 *
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * 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
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
Keith Whitwell15e75e02005-04-29 15:11:39 +000028#include "glheader.h"
29#include "macros.h"
30#include "enums.h"
31#include "texenvprogram.h"
32
33#include "shader/program.h"
34#include "shader/nvfragprog.h"
35#include "shader/arbfragparse.h"
36
37
Keith Whitwell269e3892005-05-12 10:28:43 +000038#define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
Keith Whitwell15e75e02005-04-29 15:11:39 +000039
40/* Use uregs to represent registers internally, translate to Mesa's
41 * expected formats on emit.
42 *
43 * NOTE: These are passed by value extensively in this file rather
44 * than as usual by pointer reference. If this disturbs you, try
45 * remembering they are just 32bits in size.
46 *
47 * GCC is smart enough to deal with these dword-sized structures in
48 * much the same way as if I had defined them as dwords and was using
49 * macros to access and set the fields. This is much nicer and easier
50 * to evolve.
51 */
52struct ureg {
53 GLuint file:4;
54 GLuint idx:8;
55 GLuint negatebase:1;
56 GLuint abs:1;
57 GLuint negateabs:1;
58 GLuint swz:12;
59 GLuint pad:5;
60};
61
62const static struct ureg undef = {
63 ~0,
64 ~0,
65 0,
66 0,
67 0,
68 0,
69 0
70};
71
72#define X 0
73#define Y 1
74#define Z 2
75#define W 3
76
Keith Whitwell15e75e02005-04-29 15:11:39 +000077/* State used to build the fragment program:
78 */
79struct texenv_fragment_program {
Keith Whitwell47b29f52005-05-04 11:44:44 +000080 struct fragment_program *program;
Keith Whitwell15e75e02005-04-29 15:11:39 +000081 GLcontext *ctx;
82
Keith Whitwellcf4f3c52005-05-16 12:15:01 +000083 GLuint alu_temps; /* Track texture indirections, see spec. */
84 GLuint temps_output; /* Track texture indirections, see spec. */
Keith Whitwellecb6bfc2005-05-10 08:58:44 +000085
Keith Whitwell93cd9232005-05-11 08:30:23 +000086 GLuint temp_in_use; /* Tracks temporary regs which are in
Keith Whitwell15e75e02005-04-29 15:11:39 +000087 * use.
88 */
89
90
Keith Whitwell15e75e02005-04-29 15:11:39 +000091 GLboolean error;
92
Keith Whitwell2dea6df2005-05-23 09:37:32 +000093 struct ureg src_texture[MAX_TEXTURE_UNITS];
94 /* Reg containing each texture unit's sampled texture color,
95 * else undef.
96 */
Keith Whitwell15e75e02005-04-29 15:11:39 +000097
98 struct ureg src_previous; /* Reg containing color from previous
99 * stage. May need to be decl'd.
100 */
101
102 GLuint last_tex_stage; /* Number of last enabled texture unit */
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000103
104 struct ureg half;
105 struct ureg one;
106 struct ureg zero;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000107};
108
109
110
111static struct ureg make_ureg(GLuint file, GLuint idx)
112{
113 struct ureg reg;
114 reg.file = file;
115 reg.idx = idx;
116 reg.negatebase = 0;
117 reg.abs = 0;
118 reg.negateabs = 0;
119 reg.swz = SWIZZLE_NOOP;
120 reg.pad = 0;
121 return reg;
122}
123
124static struct ureg swizzle( struct ureg reg, int x, int y, int z, int w )
125{
126 reg.swz = MAKE_SWIZZLE4(GET_SWZ(reg.swz, x),
127 GET_SWZ(reg.swz, y),
128 GET_SWZ(reg.swz, z),
129 GET_SWZ(reg.swz, w));
130
131 return reg;
132}
133
134static struct ureg swizzle1( struct ureg reg, int x )
135{
136 return swizzle(reg, x, x, x, x);
137}
138
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000139static struct ureg negate( struct ureg reg )
140{
141 reg.negatebase ^= 1;
142 return reg;
143}
144
Keith Whitwell15e75e02005-04-29 15:11:39 +0000145static GLboolean is_undef( struct ureg reg )
146{
147 return reg.file == 0xf;
148}
149
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000150
Keith Whitwell15e75e02005-04-29 15:11:39 +0000151static struct ureg get_temp( struct texenv_fragment_program *p )
152{
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000153 int bit;
154
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000155 /* First try and reuse temps which have been used already:
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000156 */
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000157 bit = ffs( ~p->temp_in_use & p->alu_temps );
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000158
159 /* Then any unused temporary:
160 */
161 if (!bit)
Keith Whitwell93cd9232005-05-11 08:30:23 +0000162 bit = ffs( ~p->temp_in_use );
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000163
Keith Whitwell15e75e02005-04-29 15:11:39 +0000164 if (!bit) {
165 fprintf(stderr, "%s: out of temporaries\n", __FILE__);
166 exit(1);
167 }
168
Keith Whitwell93cd9232005-05-11 08:30:23 +0000169 p->temp_in_use |= 1<<(bit-1);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000170 return make_ureg(PROGRAM_TEMPORARY, (bit-1));
171}
172
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000173static struct ureg get_tex_temp( struct texenv_fragment_program *p )
174{
175 int bit;
176
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000177 /* First try to find availble temp not previously used (to avoid
178 * starting a new texture indirection). According to the spec, the
179 * ~p->temps_output isn't necessary, but will keep it there for
180 * now:
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000181 */
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000182 bit = ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output );
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000183
184 /* Then any unused temporary:
185 */
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000186 if (!bit)
Keith Whitwell93cd9232005-05-11 08:30:23 +0000187 bit = ffs( ~p->temp_in_use );
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000188
189 if (!bit) {
190 fprintf(stderr, "%s: out of temporaries\n", __FILE__);
191 exit(1);
192 }
193
Keith Whitwell93cd9232005-05-11 08:30:23 +0000194 p->temp_in_use |= 1<<(bit-1);
Keith Whitwellecb6bfc2005-05-10 08:58:44 +0000195 return make_ureg(PROGRAM_TEMPORARY, (bit-1));
196}
197
Keith Whitwell15e75e02005-04-29 15:11:39 +0000198
199static void release_temps( struct texenv_fragment_program *p )
200{
Keith Whitwell93cd9232005-05-11 08:30:23 +0000201 GLuint max_temp = p->ctx->Const.MaxFragmentProgramTemps;
202
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000203 /* KW: To support tex_env_crossbar, don't release the registers in
204 * temps_output.
205 */
Keith Whitwell93cd9232005-05-11 08:30:23 +0000206 if (max_temp >= sizeof(int) * 8)
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000207 p->temp_in_use = p->temps_output;
Keith Whitwell93cd9232005-05-11 08:30:23 +0000208 else
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000209 p->temp_in_use = ~((1<<max_temp)-1) | p->temps_output;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000210}
211
212
Keith Whitwell47b29f52005-05-04 11:44:44 +0000213static struct ureg register_param6( struct texenv_fragment_program *p,
214 GLint s0,
215 GLint s1,
216 GLint s2,
217 GLint s3,
218 GLint s4,
219 GLint s5)
Keith Whitwell15e75e02005-04-29 15:11:39 +0000220{
Keith Whitwell47b29f52005-05-04 11:44:44 +0000221 GLint tokens[6];
222 GLuint idx;
223 tokens[0] = s0;
224 tokens[1] = s1;
225 tokens[2] = s2;
226 tokens[3] = s3;
227 tokens[4] = s4;
228 tokens[5] = s5;
229 idx = _mesa_add_state_reference( p->program->Parameters, tokens );
230 return make_ureg(PROGRAM_STATE_VAR, idx);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000231}
232
Keith Whitwell47b29f52005-05-04 11:44:44 +0000233
234#define register_param1(p,s0) register_param6(p,s0,0,0,0,0,0)
235#define register_param2(p,s0,s1) register_param6(p,s0,s1,0,0,0,0)
236#define register_param3(p,s0,s1,s2) register_param6(p,s0,s1,s2,0,0,0)
237#define register_param4(p,s0,s1,s2,s3) register_param6(p,s0,s1,s2,s3,0,0)
238
239
240static struct ureg register_input( struct texenv_fragment_program *p, GLuint input )
241{
242 p->program->InputsRead |= (1<<input);
243 return make_ureg(PROGRAM_INPUT, input);
244}
245
246
Keith Whitwell15e75e02005-04-29 15:11:39 +0000247static void emit_arg( struct fp_src_register *reg,
248 struct ureg ureg )
249{
250 reg->File = ureg.file;
251 reg->Index = ureg.idx;
252 reg->Swizzle = ureg.swz;
253 reg->NegateBase = ureg.negatebase;
254 reg->Abs = ureg.abs;
255 reg->NegateAbs = ureg.negateabs;
256}
257
258static void emit_dst( struct fp_dst_register *dst,
259 struct ureg ureg, GLuint mask )
260{
261 dst->File = ureg.file;
262 dst->Index = ureg.idx;
263 dst->WriteMask = mask;
264 dst->CondMask = 0;
265 dst->CondSwizzle = 0;
266}
267
268static struct fp_instruction *
269emit_op(struct texenv_fragment_program *p,
270 GLuint op,
271 struct ureg dest,
272 GLuint mask,
273 GLuint saturate,
274 struct ureg src0,
275 struct ureg src1,
276 struct ureg src2 )
277{
Keith Whitwell47b29f52005-05-04 11:44:44 +0000278 GLuint nr = p->program->Base.NumInstructions++;
279 struct fp_instruction *inst = &p->program->Instructions[nr];
Keith Whitwell15e75e02005-04-29 15:11:39 +0000280
281 memset(inst, 0, sizeof(*inst));
282 inst->Opcode = op;
283
Keith Whitwell47b29f52005-05-04 11:44:44 +0000284 emit_arg( &inst->SrcReg[0], src0 );
285 emit_arg( &inst->SrcReg[1], src1 );
286 emit_arg( &inst->SrcReg[2], src2 );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000287
288 inst->Saturate = saturate;
289
290 emit_dst( &inst->DstReg, dest, mask );
291
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000292 /* Accounting for indirection tracking:
293 */
294 if (dest.file == PROGRAM_TEMPORARY)
295 p->temps_output |= 1 << dest.idx;
296
Keith Whitwell15e75e02005-04-29 15:11:39 +0000297 return inst;
298}
299
300
301static struct ureg emit_arith( struct texenv_fragment_program *p,
Keith Whitwell47b29f52005-05-04 11:44:44 +0000302 GLuint op,
303 struct ureg dest,
304 GLuint mask,
305 GLuint saturate,
306 struct ureg src0,
307 struct ureg src1,
308 struct ureg src2 )
Keith Whitwell15e75e02005-04-29 15:11:39 +0000309{
310 emit_op(p, op, dest, mask, saturate, src0, src1, src2);
311
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000312 /* Accounting for indirection tracking:
313 */
314 if (src0.file == PROGRAM_TEMPORARY)
315 p->alu_temps |= 1 << src0.idx;
316
317 if (!is_undef(src1) && src1.file == PROGRAM_TEMPORARY)
318 p->alu_temps |= 1 << src1.idx;
319
320 if (!is_undef(src2) && src2.file == PROGRAM_TEMPORARY)
321 p->alu_temps |= 1 << src2.idx;
322
323 if (dest.file == PROGRAM_TEMPORARY)
324 p->alu_temps |= 1 << dest.idx;
325
Keith Whitwell47b29f52005-05-04 11:44:44 +0000326 p->program->NumAluInstructions++;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000327 return dest;
328}
329
330static struct ureg emit_texld( struct texenv_fragment_program *p,
331 GLuint op,
332 struct ureg dest,
333 GLuint destmask,
334 GLuint tex_unit,
335 GLuint tex_idx,
336 struct ureg coord )
337{
338 struct fp_instruction *inst = emit_op( p, op,
339 dest, destmask,
340 0, /* don't saturate? */
341 coord, /* arg 0? */
342 undef,
343 undef);
344
345 inst->TexSrcIdx = tex_idx;
346 inst->TexSrcUnit = tex_unit;
347
Keith Whitwell47b29f52005-05-04 11:44:44 +0000348 p->program->NumTexInstructions++;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000349
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000350 /* Is this a texture indirection?
351 */
352 if ((coord.file == PROGRAM_TEMPORARY &&
353 (p->temps_output & (1<<coord.idx))) ||
354 (dest.file == PROGRAM_TEMPORARY &&
355 (p->alu_temps & (1<<dest.idx)))) {
Keith Whitwell47b29f52005-05-04 11:44:44 +0000356 p->program->NumTexIndirections++;
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000357 p->temps_output = 1<<coord.idx;
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000358 p->alu_temps = 0;
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000359 assert(0); /* KW: texture env crossbar */
Keith Whitwell15e75e02005-04-29 15:11:39 +0000360 }
361
362 return dest;
363}
364
365
Keith Whitwell47b29f52005-05-04 11:44:44 +0000366static struct ureg register_const4f( struct texenv_fragment_program *p,
367 GLfloat s0,
368 GLfloat s1,
369 GLfloat s2,
370 GLfloat s3)
Keith Whitwell15e75e02005-04-29 15:11:39 +0000371{
Keith Whitwell47b29f52005-05-04 11:44:44 +0000372 GLfloat values[4];
373 GLuint idx;
374 values[0] = s0;
375 values[1] = s1;
376 values[2] = s2;
377 values[3] = s3;
378 idx = _mesa_add_unnamed_constant( p->program->Parameters, values );
379 return make_ureg(PROGRAM_STATE_VAR, idx);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000380}
381
Keith Whitwelle4902422005-05-11 15:16:35 +0000382#define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0)
Keith Whitwell47b29f52005-05-04 11:44:44 +0000383#define register_const1f(p, s0) register_const4f(p, s0, 0, 0, 1)
384#define register_const2f(p, s0, s1) register_const4f(p, s0, s1, 0, 1)
385#define register_const3f(p, s0, s1, s2) register_const4f(p, s0, s1, s2, 1)
Keith Whitwell15e75e02005-04-29 15:11:39 +0000386
387
388
Keith Whitwell15e75e02005-04-29 15:11:39 +0000389
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000390static struct ureg get_one( struct texenv_fragment_program *p )
391{
392 if (is_undef(p->one))
393 p->one = register_scalar_const(p, 1.0);
394 return p->one;
395}
396
397static struct ureg get_half( struct texenv_fragment_program *p )
398{
399 if (is_undef(p->half))
400 p->one = register_scalar_const(p, 0.5);
401 return p->half;
402}
403
404static struct ureg get_zero( struct texenv_fragment_program *p )
405{
406 if (is_undef(p->zero))
407 p->one = register_scalar_const(p, 0.0);
408 return p->zero;
409}
410
Keith Whitwell15e75e02005-04-29 15:11:39 +0000411
412
413
414
415static void program_error( struct texenv_fragment_program *p, const char *msg )
416{
417 fprintf(stderr, "%s\n", msg);
418 p->error = 1;
419}
420
421
422static GLuint translate_tex_src_bit( struct texenv_fragment_program *p,
423 GLuint bit )
424{
425 switch (bit) {
426 case TEXTURE_1D_BIT: return TEXTURE_1D_INDEX;
427 case TEXTURE_2D_BIT: return TEXTURE_2D_INDEX;
428 case TEXTURE_RECT_BIT: return TEXTURE_RECT_INDEX;
429 case TEXTURE_3D_BIT: return TEXTURE_3D_INDEX;
430 case TEXTURE_CUBE_BIT: return TEXTURE_CUBE_INDEX;
431 default: program_error(p, "TexSrcBit"); return 0;
432 }
433}
434
435
436static struct ureg get_source( struct texenv_fragment_program *p,
437 GLenum src, GLuint unit )
438{
439 switch (src) {
440 case GL_TEXTURE:
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000441 assert(!is_undef(p->src_texture[unit]));
442 return p->src_texture[unit];
Keith Whitwell15e75e02005-04-29 15:11:39 +0000443
Keith Whitwell15e75e02005-04-29 15:11:39 +0000444 case GL_TEXTURE0:
445 case GL_TEXTURE1:
446 case GL_TEXTURE2:
447 case GL_TEXTURE3:
448 case GL_TEXTURE4:
449 case GL_TEXTURE5:
450 case GL_TEXTURE6:
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000451 case GL_TEXTURE7:
452 assert(!is_undef(p->src_texture[src - GL_TEXTURE0]));
453 return p->src_texture[src - GL_TEXTURE0];
Keith Whitwell15e75e02005-04-29 15:11:39 +0000454
455 case GL_CONSTANT:
Keith Whitwell47b29f52005-05-04 11:44:44 +0000456 return register_param2(p, STATE_TEXENV_COLOR, unit);
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000457
Keith Whitwell15e75e02005-04-29 15:11:39 +0000458 case GL_PRIMARY_COLOR:
Keith Whitwell47b29f52005-05-04 11:44:44 +0000459 return register_input(p, FRAG_ATTRIB_COL0);
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000460
Keith Whitwell15e75e02005-04-29 15:11:39 +0000461 case GL_PREVIOUS:
462 default:
Keith Whitwell47b29f52005-05-04 11:44:44 +0000463 if (is_undef(p->src_previous))
464 return register_input(p, FRAG_ATTRIB_COL0);
465 else
466 return p->src_previous;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000467 }
468}
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000469
Keith Whitwell15e75e02005-04-29 15:11:39 +0000470
471static struct ureg emit_combine_source( struct texenv_fragment_program *p,
472 GLuint mask,
473 GLuint unit,
474 GLenum source,
475 GLenum operand )
476{
477 struct ureg arg, src, one;
478
479 src = get_source(p, source, unit);
480
481 switch (operand) {
482 case GL_ONE_MINUS_SRC_COLOR:
483 /* Get unused tmp,
484 * Emit tmp = 1.0 - arg.xyzw
485 */
486 arg = get_temp( p );
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000487 one = get_one( p );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000488 return emit_arith( p, FP_OPCODE_SUB, arg, mask, 0, one, src, undef);
489
490 case GL_SRC_ALPHA:
491 if (mask == WRITEMASK_W)
492 return src;
493 else
494 return swizzle1( src, W );
495 case GL_ONE_MINUS_SRC_ALPHA:
496 /* Get unused tmp,
497 * Emit tmp = 1.0 - arg.wwww
498 */
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000499 arg = get_temp(p);
500 one = get_one(p);
501 return emit_arith(p, FP_OPCODE_SUB, arg, mask, 0,
502 one, swizzle1(src, W), undef);
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000503 case GL_ZERO:
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000504 return get_zero(p);
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000505 case GL_ONE:
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000506 return get_one(p);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000507 case GL_SRC_COLOR:
508 default:
509 return src;
510 }
511}
512
513
514
515static int nr_args( GLenum mode )
516{
517 switch (mode) {
518 case GL_REPLACE: return 1;
519 case GL_MODULATE: return 2;
520 case GL_ADD: return 2;
521 case GL_ADD_SIGNED: return 2;
522 case GL_INTERPOLATE: return 3;
523 case GL_SUBTRACT: return 2;
524 case GL_DOT3_RGB_EXT: return 2;
525 case GL_DOT3_RGBA_EXT: return 2;
526 case GL_DOT3_RGB: return 2;
527 case GL_DOT3_RGBA: return 2;
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000528 case GL_MODULATE_ADD_ATI: return 3;
529 case GL_MODULATE_SUBTRACT_ATI: return 3;
530 case GL_MODULATE_SIGNED_ADD_ATI: return 3;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000531 default: return 0;
532 }
533}
534
535
536static GLboolean args_match( struct gl_texture_unit *texUnit )
537{
538 int i, nr = nr_args(texUnit->_CurrentCombine->ModeRGB);
539
540 for (i = 0 ; i < nr ; i++) {
541 if (texUnit->_CurrentCombine->SourceA[i] != texUnit->_CurrentCombine->SourceRGB[i])
542 return GL_FALSE;
543
544 switch(texUnit->_CurrentCombine->OperandA[i]) {
545 case GL_SRC_ALPHA:
546 switch(texUnit->_CurrentCombine->OperandRGB[i]) {
547 case GL_SRC_COLOR:
548 case GL_SRC_ALPHA:
549 break;
550 default:
551 return GL_FALSE;
552 }
553 break;
554 case GL_ONE_MINUS_SRC_ALPHA:
555 switch(texUnit->_CurrentCombine->OperandRGB[i]) {
556 case GL_ONE_MINUS_SRC_COLOR:
557 case GL_ONE_MINUS_SRC_ALPHA:
558 break;
559 default:
560 return GL_FALSE;
561 }
562 break;
563 default:
564 return GL_FALSE; /* impossible */
565 }
566 }
567
568 return GL_TRUE;
569}
570
571
572static struct ureg emit_combine( struct texenv_fragment_program *p,
573 struct ureg dest,
574 GLuint mask,
575 GLuint saturate,
576 GLuint unit,
577 GLenum mode,
578 const GLenum *source,
579 const GLenum *operand)
580{
581 int nr = nr_args(mode);
582 struct ureg src[3];
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000583 struct ureg tmp, half;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000584 int i;
585
586 for (i = 0; i < nr; i++)
587 src[i] = emit_combine_source( p, mask, unit, source[i], operand[i] );
588
589 switch (mode) {
590 case GL_REPLACE:
591 if (mask == WRITEMASK_XYZW && !saturate)
592 return src[0];
593 else
594 return emit_arith( p, FP_OPCODE_MOV, dest, mask, saturate, src[0], undef, undef );
595 case GL_MODULATE:
596 return emit_arith( p, FP_OPCODE_MUL, dest, mask, saturate,
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000597 src[0], src[1], undef );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000598 case GL_ADD:
599 return emit_arith( p, FP_OPCODE_ADD, dest, mask, saturate,
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000600 src[0], src[1], undef );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000601 case GL_ADD_SIGNED:
602 /* tmp = arg0 + arg1
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000603 * result = tmp - .5
Keith Whitwell15e75e02005-04-29 15:11:39 +0000604 */
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000605 half = get_half(p);
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000606 emit_arith( p, FP_OPCODE_ADD, tmp, mask, 0, src[0], src[1], undef );
607 emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, tmp, half, undef );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000608 return dest;
609 case GL_INTERPOLATE:
610 /* Arg0 * (Arg2) + Arg1 * (1-Arg2) -- note arguments are reordered:
611 */
612 return emit_arith( p, FP_OPCODE_LRP, dest, mask, saturate, src[2], src[0], src[1] );
613
614 case GL_SUBTRACT:
615 return emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, src[0], src[1], undef );
616
617 case GL_DOT3_RGBA:
618 case GL_DOT3_RGBA_EXT:
619 case GL_DOT3_RGB_EXT:
620 case GL_DOT3_RGB: {
621 struct ureg tmp0 = get_temp( p );
622 struct ureg tmp1 = get_temp( p );
Keith Whitwelle4902422005-05-11 15:16:35 +0000623 struct ureg neg1 = register_scalar_const(p, -1);
624 struct ureg two = register_scalar_const(p, 2);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000625
626 /* tmp0 = 2*src0 - 1
627 * tmp1 = 2*src1 - 1
628 *
629 * dst = tmp0 dot3 tmp1
630 */
631 emit_arith( p, FP_OPCODE_MAD, tmp0, WRITEMASK_XYZW, 0,
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000632 two, src[0], neg1);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000633
634 if (memcmp(&src[0], &src[1], sizeof(struct ureg)) == 0)
635 tmp1 = tmp0;
636 else
637 emit_arith( p, FP_OPCODE_MAD, tmp1, WRITEMASK_XYZW, 0,
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000638 two, src[1], neg1);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000639 emit_arith( p, FP_OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef);
640 return dest;
641 }
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000642 case GL_MODULATE_ADD_ATI:
643 /* Arg0 * Arg2 + Arg1 */
644 return emit_arith( p, FP_OPCODE_MAD, dest, mask, saturate,
645 src[0], src[2], src[1] );
646 case GL_MODULATE_SIGNED_ADD_ATI: {
647 /* Arg0 * Arg2 + Arg1 - 0.5 */
648 struct ureg tmp0 = get_temp(p);
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000649 half = get_half(p);
Keith Whitwell6fe176a2005-05-23 08:08:43 +0000650 emit_arith( p, FP_OPCODE_MAD, tmp0, mask, 0, src[0], src[2], src[1] );
651 emit_arith( p, FP_OPCODE_SUB, dest, mask, saturate, tmp0, half, undef );
652 return dest;
653 }
654 case GL_MODULATE_SUBTRACT_ATI:
655 /* Arg0 * Arg2 - Arg1 */
656 emit_arith( p, FP_OPCODE_MAD, dest, mask, 0, src[0], src[2], negate(src[1]) );
657 return dest;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000658 default:
659 return src[0];
660 }
661}
662
Keith Whitwell15e75e02005-04-29 15:11:39 +0000663
Keith Whitwell15e75e02005-04-29 15:11:39 +0000664static struct ureg emit_texenv( struct texenv_fragment_program *p, int unit )
665{
666 struct gl_texture_unit *texUnit = &p->ctx->Texture.Unit[unit];
667 GLuint saturate = (unit < p->last_tex_stage);
668 GLuint rgb_shift, alpha_shift;
669 struct ureg out, shift;
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000670 struct ureg dest;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000671
672 if (!texUnit->_ReallyEnabled) {
673 return get_source(p, GL_PREVIOUS, 0);
674 }
675
676 switch (texUnit->_CurrentCombine->ModeRGB) {
677 case GL_DOT3_RGB_EXT:
678 alpha_shift = texUnit->_CurrentCombine->ScaleShiftA;
679 rgb_shift = 0;
680 break;
681
682 case GL_DOT3_RGBA_EXT:
683 alpha_shift = 0;
684 rgb_shift = 0;
685 break;
686
687 default:
688 rgb_shift = texUnit->_CurrentCombine->ScaleShiftRGB;
689 alpha_shift = texUnit->_CurrentCombine->ScaleShiftA;
690 break;
691 }
692
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000693 /* If this is the very last calculation, emit direct to output reg:
694 */
695 if ((p->ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) ||
696 unit != p->last_tex_stage ||
697 alpha_shift ||
698 rgb_shift)
699 dest = get_temp( p );
700 else
701 dest = make_ureg(PROGRAM_OUTPUT, FRAG_OUTPUT_COLR);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000702
703 /* Emit the RGB and A combine ops
704 */
705 if (texUnit->_CurrentCombine->ModeRGB == texUnit->_CurrentCombine->ModeA &&
706 args_match( texUnit )) {
707 out = emit_combine( p, dest, WRITEMASK_XYZW, saturate,
708 unit,
709 texUnit->_CurrentCombine->ModeRGB,
710 texUnit->_CurrentCombine->SourceRGB,
711 texUnit->_CurrentCombine->OperandRGB );
712 }
713 else if (texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA_EXT ||
714 texUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA) {
715
716 out = emit_combine( p, dest, WRITEMASK_XYZW, saturate,
717 unit,
718 texUnit->_CurrentCombine->ModeRGB,
719 texUnit->_CurrentCombine->SourceRGB,
720 texUnit->_CurrentCombine->OperandRGB );
721 }
722 else {
723 /* Need to do something to stop from re-emitting identical
724 * argument calculations here:
725 */
726 out = emit_combine( p, dest, WRITEMASK_XYZ, saturate,
727 unit,
728 texUnit->_CurrentCombine->ModeRGB,
729 texUnit->_CurrentCombine->SourceRGB,
730 texUnit->_CurrentCombine->OperandRGB );
731 out = emit_combine( p, dest, WRITEMASK_W, saturate,
732 unit,
733 texUnit->_CurrentCombine->ModeA,
734 texUnit->_CurrentCombine->SourceA,
735 texUnit->_CurrentCombine->OperandA );
736 }
737
738 /* Deal with the final shift:
739 */
740 if (alpha_shift || rgb_shift) {
741 if (rgb_shift == alpha_shift) {
Keith Whitwelle4902422005-05-11 15:16:35 +0000742 shift = register_scalar_const(p, 1<<rgb_shift);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000743 }
744 else {
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000745 shift = register_const4f(p,
746 1<<rgb_shift,
747 1<<rgb_shift,
748 1<<rgb_shift,
749 1<<alpha_shift);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000750 }
751 return emit_arith( p, FP_OPCODE_MUL, dest, WRITEMASK_XYZW,
752 saturate, out, shift, undef );
753 }
754 else
755 return out;
756}
757
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000758
759
760static void load_texture( struct texenv_fragment_program *p, GLuint unit )
761{
762 if (is_undef(p->src_texture[unit])) {
763 GLuint dim = translate_tex_src_bit( p, p->ctx->Texture.Unit[unit]._ReallyEnabled);
764 struct ureg texcoord = register_input(p, FRAG_ATTRIB_TEX0+unit);
765 struct ureg tmp = get_tex_temp( p );
766
767 /* TODO: Use D0_MASK_XY where possible.
768 */
769 p->src_texture[unit] = emit_texld( p, FP_OPCODE_TXP,
770 tmp, WRITEMASK_XYZW,
771 unit, dim, texcoord );
772 }
773}
774
775static void load_texenv_source( struct texenv_fragment_program *p,
776 GLenum src, GLuint unit )
777{
778 switch (src) {
779 case GL_TEXTURE:
780 load_texture(p, unit);
781 break;
782
783 case GL_TEXTURE0:
784 case GL_TEXTURE1:
785 case GL_TEXTURE2:
786 case GL_TEXTURE3:
787 case GL_TEXTURE4:
788 case GL_TEXTURE5:
789 case GL_TEXTURE6:
790 case GL_TEXTURE7:
791 load_texture(p, src - GL_TEXTURE0);
792 break;
793
794 default:
795 break;
796 }
797}
798
799static void load_texunit_sources( struct texenv_fragment_program *p, int unit )
800{
801 struct gl_texture_unit *texUnit = &p->ctx->Texture.Unit[unit];
802 int i, nr = nr_args(texUnit->_CurrentCombine->ModeRGB);
803 for (i = 0; i < nr; i++) {
804 load_texenv_source( p, texUnit->_CurrentCombine->SourceRGB[i], unit);
805 load_texenv_source( p, texUnit->_CurrentCombine->SourceA[i], unit );
806 }
807}
808
Keith Whitwell15e75e02005-04-29 15:11:39 +0000809void _mesa_UpdateTexEnvProgram( GLcontext *ctx )
810{
811 struct texenv_fragment_program p;
812 GLuint unit;
813 struct ureg cf, out;
Keith Whitwelle4902422005-05-11 15:16:35 +0000814 GLuint db_NumInstructions = 0;
815 struct fp_instruction *db_Instructions = NULL;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000816
Keith Whitwell47b29f52005-05-04 11:44:44 +0000817 if (ctx->FragmentProgram._Enabled)
818 return;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000819
Keith Whitwell8b88f622005-05-10 11:39:50 +0000820 if (!ctx->_TexEnvProgram)
821 ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
822 (struct fragment_program *)
823 ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
Keith Whitwell276330b2005-05-09 17:58:13 +0000824
Keith Whitwelle4902422005-05-11 15:16:35 +0000825 _mesa_memset(&p, 0, sizeof(p));
Keith Whitwell47b29f52005-05-04 11:44:44 +0000826 p.ctx = ctx;
Keith Whitwell276330b2005-05-09 17:58:13 +0000827 p.program = ctx->_TexEnvProgram;
Keith Whitwell47b29f52005-05-04 11:44:44 +0000828
Keith Whitwelle4902422005-05-11 15:16:35 +0000829 if (ctx->Driver.ProgramStringNotify || DISASSEM) {
830 db_Instructions = p.program->Instructions;
831 db_NumInstructions = p.program->Base.NumInstructions;
832 p.program->Instructions = NULL;
833 }
Keith Whitwell15e75e02005-04-29 15:11:39 +0000834
Keith Whitwelle4902422005-05-11 15:16:35 +0000835 if (!p.program->Instructions)
836 p.program->Instructions = MALLOC(sizeof(struct fp_instruction) * 100);
837
Keith Whitwell47b29f52005-05-04 11:44:44 +0000838 p.program->Base.NumInstructions = 0;
Keith Whitwell276330b2005-05-09 17:58:13 +0000839 p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB;
Keith Whitwell47b29f52005-05-04 11:44:44 +0000840 p.program->NumTexIndirections = 1; /* correct? */
841 p.program->NumTexInstructions = 0;
842 p.program->NumAluInstructions = 0;
Keith Whitwell9ca88152005-05-10 09:56:02 +0000843 p.program->Base.String = 0;
844 p.program->Base.NumInstructions =
845 p.program->Base.NumTemporaries =
846 p.program->Base.NumParameters =
847 p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0;
Keith Whitwell93cd9232005-05-11 08:30:23 +0000848
Keith Whitwell9ca88152005-05-10 09:56:02 +0000849 if (p.program->Parameters)
Keith Whitwelldbeea252005-05-10 13:57:50 +0000850 _mesa_free_parameters(p.program->Parameters);
851 else
852 p.program->Parameters = _mesa_new_parameter_list();
853
Keith Whitwell9ca88152005-05-10 09:56:02 +0000854 p.program->InputsRead = 0;
Keith Whitwellcf4f3c52005-05-16 12:15:01 +0000855 p.program->OutputsWritten = 1 << FRAG_OUTPUT_COLR;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000856
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000857 for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++)
858 p.src_texture[unit] = undef;
859
Keith Whitwell47b29f52005-05-04 11:44:44 +0000860 p.src_previous = undef;
Keith Whitwell15e75e02005-04-29 15:11:39 +0000861 p.last_tex_stage = 0;
Keith Whitwell93cd9232005-05-11 08:30:23 +0000862 release_temps(&p);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000863
864 if (ctx->Texture._EnabledUnits) {
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000865 /* First pass - to support texture_env_crossbar, first identify
866 * all referenced texture sources and emit texld instructions
867 * for each:
868 */
Keith Whitwell15e75e02005-04-29 15:11:39 +0000869 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++)
870 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000871 load_texunit_sources( &p, unit );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000872 p.last_tex_stage = unit;
873 }
874
Keith Whitwell2dea6df2005-05-23 09:37:32 +0000875 /* Second pass - emit combine instructions to build final color:
876 */
Keith Whitwell15e75e02005-04-29 15:11:39 +0000877 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++)
878 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
879 p.src_previous = emit_texenv( &p, unit );
Keith Whitwell93cd9232005-05-11 08:30:23 +0000880 release_temps(&p); /* release all temps */
Keith Whitwell15e75e02005-04-29 15:11:39 +0000881 }
882 }
883
884 cf = get_source( &p, GL_PREVIOUS, 0 );
Keith Whitwell47b29f52005-05-04 11:44:44 +0000885 out = make_ureg( PROGRAM_OUTPUT, FRAG_OUTPUT_COLR );
Keith Whitwell15e75e02005-04-29 15:11:39 +0000886
887 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
888 /* Emit specular add.
889 */
Keith Whitwell47b29f52005-05-04 11:44:44 +0000890 struct ureg s = register_input(&p, FRAG_ATTRIB_COL1);
Keith Whitwell15e75e02005-04-29 15:11:39 +0000891 emit_arith( &p, FP_OPCODE_ADD, out, WRITEMASK_XYZ, 0, cf, s, undef );
892 }
893 else if (memcmp(&cf, &out, sizeof(cf)) != 0) {
894 /* Will wind up in here if no texture enabled or a couple of
895 * other scenarios (GL_REPLACE for instance).
896 */
897 emit_arith( &p, FP_OPCODE_MOV, out, WRITEMASK_XYZW, 0, cf, undef, undef );
898 }
899
Keith Whitwell47b29f52005-05-04 11:44:44 +0000900 /* Finish up:
901 */
902 emit_arith( &p, FP_OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef);
903
Keith Whitwell276330b2005-05-09 17:58:13 +0000904 if (ctx->Fog.Enabled)
905 p.program->FogOption = ctx->Fog.Mode;
906 else
907 p.program->FogOption = GL_NONE;
Keith Whitwell47b29f52005-05-04 11:44:44 +0000908
909 if (p.program->NumTexIndirections > ctx->Const.MaxFragmentProgramTexIndirections)
Keith Whitwell15e75e02005-04-29 15:11:39 +0000910 program_error(&p, "Exceeded max nr indirect texture lookups");
911
Keith Whitwell47b29f52005-05-04 11:44:44 +0000912 if (p.program->NumTexInstructions > ctx->Const.MaxFragmentProgramTexInstructions)
Keith Whitwell15e75e02005-04-29 15:11:39 +0000913 program_error(&p, "Exceeded max TEX instructions");
914
Keith Whitwell47b29f52005-05-04 11:44:44 +0000915 if (p.program->NumAluInstructions > ctx->Const.MaxFragmentProgramAluInstructions)
Keith Whitwell15e75e02005-04-29 15:11:39 +0000916 program_error(&p, "Exceeded max ALU instructions");
917
Keith Whitwell8b88f622005-05-10 11:39:50 +0000918
Keith Whitwelldbeea252005-05-10 13:57:50 +0000919 /* Notify driver the fragment program has (actually) changed.
Keith Whitwell8b88f622005-05-10 11:39:50 +0000920 */
Keith Whitwelle4902422005-05-11 15:16:35 +0000921 if (ctx->Driver.ProgramStringNotify || DISASSEM) {
922 if (db_Instructions == NULL ||
923 db_NumInstructions != p.program->Base.NumInstructions ||
924 memcmp(db_Instructions, p.program->Instructions,
925 db_NumInstructions * sizeof(*db_Instructions)) != 0) {
926
927 if (ctx->Driver.ProgramStringNotify)
928 ctx->Driver.ProgramStringNotify( ctx, GL_FRAGMENT_PROGRAM_ARB,
929 &p.program->Base );
Keith Whitwelldbeea252005-05-10 13:57:50 +0000930
Keith Whitwelle4902422005-05-11 15:16:35 +0000931 if (DISASSEM) {
932 _mesa_debug_fp_inst(p.program->NumTexInstructions + p.program->NumAluInstructions,
933 p.program->Instructions);
934 _mesa_printf("\n");
935 }
936 }
937
938 FREE(db_Instructions);
939 }
Keith Whitwell15e75e02005-04-29 15:11:39 +0000940}
941
942