Support ARB_texture_env_crossbar. Changes the way programs are
[mesa.git] / src / mesa / main / texenvprogram.c
1 /**************************************************************************
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
28 #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
38 #define DISASSEM (MESA_VERBOSE & VERBOSE_DISASSEM)
39
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 */
52 struct 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
62 const 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
77 /* State used to build the fragment program:
78 */
79 struct texenv_fragment_program {
80 struct fragment_program *program;
81 GLcontext *ctx;
82
83 GLuint alu_temps; /* Track texture indirections, see spec. */
84 GLuint temps_output; /* Track texture indirections, see spec. */
85
86 GLuint temp_in_use; /* Tracks temporary regs which are in
87 * use.
88 */
89
90
91 GLboolean error;
92
93 struct ureg src_texture[MAX_TEXTURE_UNITS];
94 /* Reg containing each texture unit's sampled texture color,
95 * else undef.
96 */
97
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 */
103
104 struct ureg half;
105 struct ureg one;
106 struct ureg zero;
107 };
108
109
110
111 static 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
124 static 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
134 static struct ureg swizzle1( struct ureg reg, int x )
135 {
136 return swizzle(reg, x, x, x, x);
137 }
138
139 static struct ureg negate( struct ureg reg )
140 {
141 reg.negatebase ^= 1;
142 return reg;
143 }
144
145 static GLboolean is_undef( struct ureg reg )
146 {
147 return reg.file == 0xf;
148 }
149
150
151 static struct ureg get_temp( struct texenv_fragment_program *p )
152 {
153 int bit;
154
155 /* First try and reuse temps which have been used already:
156 */
157 bit = ffs( ~p->temp_in_use & p->alu_temps );
158
159 /* Then any unused temporary:
160 */
161 if (!bit)
162 bit = ffs( ~p->temp_in_use );
163
164 if (!bit) {
165 fprintf(stderr, "%s: out of temporaries\n", __FILE__);
166 exit(1);
167 }
168
169 p->temp_in_use |= 1<<(bit-1);
170 return make_ureg(PROGRAM_TEMPORARY, (bit-1));
171 }
172
173 static struct ureg get_tex_temp( struct texenv_fragment_program *p )
174 {
175 int bit;
176
177 /* 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:
181 */
182 bit = ffs( ~p->temp_in_use & ~p->alu_temps & ~p->temps_output );
183
184 /* Then any unused temporary:
185 */
186 if (!bit)
187 bit = ffs( ~p->temp_in_use );
188
189 if (!bit) {
190 fprintf(stderr, "%s: out of temporaries\n", __FILE__);
191 exit(1);
192 }
193
194 p->temp_in_use |= 1<<(bit-1);
195 return make_ureg(PROGRAM_TEMPORARY, (bit-1));
196 }
197
198
199 static void release_temps( struct texenv_fragment_program *p )
200 {
201 GLuint max_temp = p->ctx->Const.MaxFragmentProgramTemps;
202
203 /* KW: To support tex_env_crossbar, don't release the registers in
204 * temps_output.
205 */
206 if (max_temp >= sizeof(int) * 8)
207 p->temp_in_use = p->temps_output;
208 else
209 p->temp_in_use = ~((1<<max_temp)-1) | p->temps_output;
210 }
211
212
213 static 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)
220 {
221 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);
231 }
232
233
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
240 static 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
247 static 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
258 static 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
268 static struct fp_instruction *
269 emit_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 {
278 GLuint nr = p->program->Base.NumInstructions++;
279 struct fp_instruction *inst = &p->program->Instructions[nr];
280
281 memset(inst, 0, sizeof(*inst));
282 inst->Opcode = op;
283
284 emit_arg( &inst->SrcReg[0], src0 );
285 emit_arg( &inst->SrcReg[1], src1 );
286 emit_arg( &inst->SrcReg[2], src2 );
287
288 inst->Saturate = saturate;
289
290 emit_dst( &inst->DstReg, dest, mask );
291
292 /* Accounting for indirection tracking:
293 */
294 if (dest.file == PROGRAM_TEMPORARY)
295 p->temps_output |= 1 << dest.idx;
296
297 return inst;
298 }
299
300
301 static struct ureg emit_arith( struct texenv_fragment_program *p,
302 GLuint op,
303 struct ureg dest,
304 GLuint mask,
305 GLuint saturate,
306 struct ureg src0,
307 struct ureg src1,
308 struct ureg src2 )
309 {
310 emit_op(p, op, dest, mask, saturate, src0, src1, src2);
311
312 /* 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
326 p->program->NumAluInstructions++;
327 return dest;
328 }
329
330 static 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
348 p->program->NumTexInstructions++;
349
350 /* 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)))) {
356 p->program->NumTexIndirections++;
357 p->temps_output = 1<<coord.idx;
358 p->alu_temps = 0;
359 assert(0); /* KW: texture env crossbar */
360 }
361
362 return dest;
363 }
364
365
366 static struct ureg register_const4f( struct texenv_fragment_program *p,
367 GLfloat s0,
368 GLfloat s1,
369 GLfloat s2,
370 GLfloat s3)
371 {
372 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);
380 }
381
382 #define register_scalar_const(p, s0) register_const4f(p, s0, s0, s0, s0)
383 #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)
386
387
388
389
390 static 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
397 static 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
404 static 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
411
412
413
414
415 static 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
422 static 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
436 static struct ureg get_source( struct texenv_fragment_program *p,
437 GLenum src, GLuint unit )
438 {
439 switch (src) {
440 case GL_TEXTURE:
441 assert(!is_undef(p->src_texture[unit]));
442 return p->src_texture[unit];
443
444 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:
451 case GL_TEXTURE7:
452 assert(!is_undef(p->src_texture[src - GL_TEXTURE0]));
453 return p->src_texture[src - GL_TEXTURE0];
454
455 case GL_CONSTANT:
456 return register_param2(p, STATE_TEXENV_COLOR, unit);
457
458 case GL_PRIMARY_COLOR:
459 return register_input(p, FRAG_ATTRIB_COL0);
460
461 case GL_PREVIOUS:
462 default:
463 if (is_undef(p->src_previous))
464 return register_input(p, FRAG_ATTRIB_COL0);
465 else
466 return p->src_previous;
467 }
468 }
469
470
471 static 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 );
487 one = get_one( p );
488 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 */
499 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);
503 case GL_ZERO:
504 return get_zero(p);
505 case GL_ONE:
506 return get_one(p);
507 case GL_SRC_COLOR:
508 default:
509 return src;
510 }
511 }
512
513
514
515 static 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;
528 case GL_MODULATE_ADD_ATI: return 3;
529 case GL_MODULATE_SUBTRACT_ATI: return 3;
530 case GL_MODULATE_SIGNED_ADD_ATI: return 3;
531 default: return 0;
532 }
533 }
534
535
536 static 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
572 static 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];
583 struct ureg tmp, half;
584 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,
597 src[0], src[1], undef );
598 case GL_ADD:
599 return emit_arith( p, FP_OPCODE_ADD, dest, mask, saturate,
600 src[0], src[1], undef );
601 case GL_ADD_SIGNED:
602 /* tmp = arg0 + arg1
603 * result = tmp - .5
604 */
605 half = get_half(p);
606 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 );
608 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 );
623 struct ureg neg1 = register_scalar_const(p, -1);
624 struct ureg two = register_scalar_const(p, 2);
625
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,
632 two, src[0], neg1);
633
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,
638 two, src[1], neg1);
639 emit_arith( p, FP_OPCODE_DP3, dest, mask, saturate, tmp0, tmp1, undef);
640 return dest;
641 }
642 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);
649 half = get_half(p);
650 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;
658 default:
659 return src[0];
660 }
661 }
662
663
664 static 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;
670 struct ureg dest;
671
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
693 /* 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);
702
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) {
742 shift = register_scalar_const(p, 1<<rgb_shift);
743 }
744 else {
745 shift = register_const4f(p,
746 1<<rgb_shift,
747 1<<rgb_shift,
748 1<<rgb_shift,
749 1<<alpha_shift);
750 }
751 return emit_arith( p, FP_OPCODE_MUL, dest, WRITEMASK_XYZW,
752 saturate, out, shift, undef );
753 }
754 else
755 return out;
756 }
757
758
759
760 static 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
775 static 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
799 static 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
809 void _mesa_UpdateTexEnvProgram( GLcontext *ctx )
810 {
811 struct texenv_fragment_program p;
812 GLuint unit;
813 struct ureg cf, out;
814 GLuint db_NumInstructions = 0;
815 struct fp_instruction *db_Instructions = NULL;
816
817 if (ctx->FragmentProgram._Enabled)
818 return;
819
820 if (!ctx->_TexEnvProgram)
821 ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
822 (struct fragment_program *)
823 ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
824
825 _mesa_memset(&p, 0, sizeof(p));
826 p.ctx = ctx;
827 p.program = ctx->_TexEnvProgram;
828
829 if (ctx->Driver.ProgramStringNotify || DISASSEM) {
830 db_Instructions = p.program->Instructions;
831 db_NumInstructions = p.program->Base.NumInstructions;
832 p.program->Instructions = NULL;
833 }
834
835 if (!p.program->Instructions)
836 p.program->Instructions = MALLOC(sizeof(struct fp_instruction) * 100);
837
838 p.program->Base.NumInstructions = 0;
839 p.program->Base.Target = GL_FRAGMENT_PROGRAM_ARB;
840 p.program->NumTexIndirections = 1; /* correct? */
841 p.program->NumTexInstructions = 0;
842 p.program->NumAluInstructions = 0;
843 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;
848
849 if (p.program->Parameters)
850 _mesa_free_parameters(p.program->Parameters);
851 else
852 p.program->Parameters = _mesa_new_parameter_list();
853
854 p.program->InputsRead = 0;
855 p.program->OutputsWritten = 1 << FRAG_OUTPUT_COLR;
856
857 for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++)
858 p.src_texture[unit] = undef;
859
860 p.src_previous = undef;
861 p.last_tex_stage = 0;
862 release_temps(&p);
863
864 if (ctx->Texture._EnabledUnits) {
865 /* First pass - to support texture_env_crossbar, first identify
866 * all referenced texture sources and emit texld instructions
867 * for each:
868 */
869 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++)
870 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
871 load_texunit_sources( &p, unit );
872 p.last_tex_stage = unit;
873 }
874
875 /* Second pass - emit combine instructions to build final color:
876 */
877 for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++)
878 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
879 p.src_previous = emit_texenv( &p, unit );
880 release_temps(&p); /* release all temps */
881 }
882 }
883
884 cf = get_source( &p, GL_PREVIOUS, 0 );
885 out = make_ureg( PROGRAM_OUTPUT, FRAG_OUTPUT_COLR );
886
887 if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
888 /* Emit specular add.
889 */
890 struct ureg s = register_input(&p, FRAG_ATTRIB_COL1);
891 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
900 /* Finish up:
901 */
902 emit_arith( &p, FP_OPCODE_END, undef, WRITEMASK_XYZW, 0, undef, undef, undef);
903
904 if (ctx->Fog.Enabled)
905 p.program->FogOption = ctx->Fog.Mode;
906 else
907 p.program->FogOption = GL_NONE;
908
909 if (p.program->NumTexIndirections > ctx->Const.MaxFragmentProgramTexIndirections)
910 program_error(&p, "Exceeded max nr indirect texture lookups");
911
912 if (p.program->NumTexInstructions > ctx->Const.MaxFragmentProgramTexInstructions)
913 program_error(&p, "Exceeded max TEX instructions");
914
915 if (p.program->NumAluInstructions > ctx->Const.MaxFragmentProgramAluInstructions)
916 program_error(&p, "Exceeded max ALU instructions");
917
918
919 /* Notify driver the fragment program has (actually) changed.
920 */
921 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 );
930
931 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 }
940 }
941
942