brw_wm_fp.c revision 9f344b3e7d6e23674dd4747faec253f103563b36
1/*
2 Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a 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, sublicense, 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
16 portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **********************************************************************/
27 /*
28  * Authors:
29  *   Keith Whitwell <keith@tungstengraphics.com>
30  */
31
32
33#include "glheader.h"
34#include "macros.h"
35#include "enums.h"
36#include "brw_context.h"
37#include "brw_wm.h"
38#include "brw_util.h"
39
40#include "shader/program.h"
41#include "shader/program_instruction.h"
42#include "shader/arbprogparse.h"
43
44#define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
45
46#define X    0
47#define Y    1
48#define Z    2
49#define W    3
50
51
52static const char *wm_opcode_strings[] = {
53   "PIXELXY",
54   "DELTAXY",
55   "PIXELW",
56   "LINTERP",
57   "PINTERP",
58   "CINTERP",
59   "WPOSXY",
60   "FB_WRITE"
61};
62
63static const char *wm_file_strings[] = {
64   "PAYLOAD"
65};
66
67
68/***********************************************************************
69 * Source regs
70 */
71
72static struct prog_src_register src_reg(GLuint file, GLuint idx)
73{
74   struct prog_src_register reg;
75   reg.File = file;
76   reg.Index = idx;
77   reg.Swizzle = SWIZZLE_NOOP;
78   reg.RelAddr = 0;
79   reg.NegateBase = 0;
80   reg.Abs = 0;
81   reg.NegateAbs = 0;
82   return reg;
83}
84
85static struct prog_src_register src_reg_from_dst(struct prog_dst_register dst)
86{
87   return src_reg(dst.File, dst.Index);
88}
89
90static struct prog_src_register src_undef( void )
91{
92   return src_reg(PROGRAM_UNDEFINED, 0);
93}
94
95static GLboolean src_is_undef(struct prog_src_register src)
96{
97   return src.File == PROGRAM_UNDEFINED;
98}
99
100static struct prog_src_register src_swizzle( struct prog_src_register reg, int x, int y, int z, int w )
101{
102   reg.Swizzle = MAKE_SWIZZLE4(x,y,z,w);
103   return reg;
104}
105
106static struct prog_src_register src_swizzle1( struct prog_src_register reg, int x )
107{
108   return src_swizzle(reg, x, x, x, x);
109}
110
111
112/***********************************************************************
113 * Dest regs
114 */
115
116static struct prog_dst_register dst_reg(GLuint file, GLuint idx)
117{
118   struct prog_dst_register reg;
119   reg.File = file;
120   reg.Index = idx;
121   reg.WriteMask = WRITEMASK_XYZW;
122   reg.CondMask = 0;
123   reg.CondSwizzle = 0;
124   reg.pad = 0;
125   reg.CondSrc = 0;
126   return reg;
127}
128
129static struct prog_dst_register dst_mask( struct prog_dst_register reg, int mask )
130{
131   reg.WriteMask &= mask;
132   return reg;
133}
134
135static struct prog_dst_register dst_undef( void )
136{
137   return dst_reg(PROGRAM_UNDEFINED, 0);
138}
139
140
141
142static struct prog_dst_register get_temp( struct brw_wm_compile *c )
143{
144   int bit = ffs( ~c->fp_temp );
145
146   if (!bit) {
147      _mesa_printf("%s: out of temporaries\n", __FILE__);
148      exit(1);
149   }
150
151   c->fp_temp |= 1<<(bit-1);
152   return dst_reg(PROGRAM_TEMPORARY, FIRST_INTERNAL_TEMP+(bit-1));
153}
154
155
156static void release_temp( struct brw_wm_compile *c, struct prog_dst_register temp )
157{
158   c->fp_temp &= ~1<<(temp.Index + 1 - FIRST_INTERNAL_TEMP);
159}
160
161
162/***********************************************************************
163 * Instructions
164 */
165
166static struct prog_instruction *get_fp_inst(struct brw_wm_compile *c)
167{
168   return &c->prog_instructions[c->nr_fp_insns++];
169}
170
171static struct prog_instruction *emit_insn(struct brw_wm_compile *c,
172					const struct prog_instruction *inst0)
173{
174   struct prog_instruction *inst = get_fp_inst(c);
175   *inst = *inst0;
176   return inst;
177}
178
179static struct prog_instruction * emit_op(struct brw_wm_compile *c,
180				       GLuint op,
181				       struct prog_dst_register dest,
182				       GLuint saturate,
183				       GLuint tex_src_unit,
184				       GLuint tex_src_target,
185				       struct prog_src_register src0,
186				       struct prog_src_register src1,
187				       struct prog_src_register src2 )
188{
189   struct prog_instruction *inst = get_fp_inst(c);
190
191   memset(inst, 0, sizeof(*inst));
192
193   inst->Opcode = op;
194   inst->DstReg = dest;
195   inst->SaturateMode = saturate;
196   inst->TexSrcUnit = tex_src_unit;
197   inst->TexSrcTarget = tex_src_target;
198   inst->SrcReg[0] = src0;
199   inst->SrcReg[1] = src1;
200   inst->SrcReg[2] = src2;
201
202   return inst;
203}
204
205
206
207
208/***********************************************************************
209 * Special instructions for interpolation and other tasks
210 */
211
212static struct prog_src_register get_pixel_xy( struct brw_wm_compile *c )
213{
214   if (src_is_undef(c->pixel_xy)) {
215      struct prog_dst_register pixel_xy = get_temp(c);
216      struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
217
218
219      /* Emit the out calculations, and hold onto the results.  Use
220       * two instructions as a temporary is required.
221       */
222      /* pixel_xy.xy = PIXELXY payload[0];
223       */
224      emit_op(c,
225	      WM_PIXELXY,
226	      dst_mask(pixel_xy, WRITEMASK_XY),
227	      0, 0, 0,
228	      payload_r0_depth,
229	      src_undef(),
230	      src_undef());
231
232      c->pixel_xy = src_reg_from_dst(pixel_xy);
233   }
234
235   return c->pixel_xy;
236}
237
238static struct prog_src_register get_delta_xy( struct brw_wm_compile *c )
239{
240   if (src_is_undef(c->delta_xy)) {
241      struct prog_dst_register delta_xy = get_temp(c);
242      struct prog_src_register pixel_xy = get_pixel_xy(c);
243      struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
244
245      /* deltas.xy = DELTAXY pixel_xy, payload[0]
246       */
247      emit_op(c,
248	      WM_DELTAXY,
249	      dst_mask(delta_xy, WRITEMASK_XY),
250	      0, 0, 0,
251	      pixel_xy,
252	      payload_r0_depth,
253	      src_undef());
254
255      c->delta_xy = src_reg_from_dst(delta_xy);
256   }
257
258   return c->delta_xy;
259}
260
261static struct prog_src_register get_pixel_w( struct brw_wm_compile *c )
262{
263   if (src_is_undef(c->pixel_w)) {
264      struct prog_dst_register pixel_w = get_temp(c);
265      struct prog_src_register deltas = get_delta_xy(c);
266      struct prog_src_register interp_wpos = src_reg(PROGRAM_PAYLOAD, FRAG_ATTRIB_WPOS);
267
268
269      /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
270       */
271      emit_op(c,
272	      WM_PIXELW,
273	      dst_mask(pixel_w, WRITEMASK_W),
274	      0, 0, 0,
275	      interp_wpos,
276	      deltas,
277	      src_undef());
278
279
280      c->pixel_w = src_reg_from_dst(pixel_w);
281   }
282
283   return c->pixel_w;
284}
285
286static void emit_interp( struct brw_wm_compile *c,
287			 GLuint idx )
288{
289   struct prog_dst_register dst = dst_reg(PROGRAM_INPUT, idx);
290   struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
291   struct prog_src_register deltas = get_delta_xy(c);
292   struct prog_src_register arg2;
293   GLuint opcode;
294
295   /* Need to use PINTERP on attributes which have been
296    * multiplied by 1/W in the SF program, and LINTERP on those
297    * which have not:
298    */
299   switch (idx) {
300   case FRAG_ATTRIB_WPOS:
301      opcode = WM_LINTERP;
302      arg2 = src_undef();
303
304      /* Have to treat wpos.xy specially:
305       */
306      emit_op(c,
307	      WM_WPOSXY,
308	      dst_mask(dst, WRITEMASK_XY),
309	      0, 0, 0,
310	      get_pixel_xy(c),
311	      src_undef(),
312	      src_undef());
313
314      dst = dst_mask(dst, WRITEMASK_ZW);
315
316      /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
317       */
318      emit_op(c,
319	      WM_LINTERP,
320	      dst,
321	      0, 0, 0,
322	      interp,
323	      deltas,
324	      arg2);
325      break;
326   case FRAG_ATTRIB_COL0:
327   case FRAG_ATTRIB_COL1:
328      if (c->key.flat_shade) {
329	 emit_op(c,
330		 WM_CINTERP,
331		 dst,
332		 0, 0, 0,
333		 interp,
334		 src_undef(),
335		 src_undef());
336      }
337      else {
338	 emit_op(c,
339		 WM_LINTERP,
340		 dst,
341		 0, 0, 0,
342		 interp,
343		 deltas,
344		 src_undef());
345      }
346      break;
347   default:
348      emit_op(c,
349	      WM_PINTERP,
350	      dst,
351	      0, 0, 0,
352	      interp,
353	      deltas,
354	      get_pixel_w(c));
355      break;
356   }
357
358   c->fp_interp_emitted |= 1<<idx;
359}
360
361
362/***********************************************************************
363 * Hacks to extend the program parameter and constant lists.
364 */
365
366/* Add the fog parameters to the parameter list of the original
367 * program, rather than creating a new list.  Doesn't really do any
368 * harm and it's not as if the parameter handling isn't a big hack
369 * anyway.
370 */
371static struct prog_src_register search_or_add_param6( struct brw_wm_compile *c,
372					     GLint s0,
373					     GLint s1,
374					     GLint s2,
375					     GLint s3,
376					     GLint s4,
377					     GLint s5)
378{
379   struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
380   GLint tokens[6];
381   GLuint idx;
382   tokens[0] = s0;
383   tokens[1] = s1;
384   tokens[2] = s2;
385   tokens[3] = s3;
386   tokens[4] = s4;
387   tokens[5] = s5;
388
389   for (idx = 0; idx < paramList->NumParameters; idx++) {
390      if (paramList->Parameters[idx].Type == PROGRAM_STATE_VAR &&
391	  memcmp(paramList->Parameters[idx].StateIndexes, tokens, sizeof(tokens)) == 0)
392	 return src_reg(PROGRAM_STATE_VAR, idx);
393   }
394
395   idx = _mesa_add_state_reference( paramList, tokens );
396
397   /* Recalculate state dependency:
398    */
399   c->fp->param_state = brw_parameter_list_state_flags( paramList );
400
401   return src_reg(PROGRAM_STATE_VAR, idx);
402}
403
404
405static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
406						     GLfloat s0,
407						     GLfloat s1,
408						     GLfloat s2,
409						     GLfloat s3)
410{
411   struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
412   GLfloat values[4];
413   GLuint idx;
414
415   values[0] = s0;
416   values[1] = s1;
417   values[2] = s2;
418   values[3] = s3;
419
420   /* Have to search, otherwise multiple compilations will each grow
421    * the parameter list.
422    */
423   for (idx = 0; idx < paramList->NumParameters; idx++) {
424      if (paramList->Parameters[idx].Type == PROGRAM_CONSTANT &&
425	  memcmp(paramList->ParameterValues[idx], values, sizeof(values)) == 0)
426
427	 /* XXX: this mimics the mesa bug which puts all constants and
428	  * parameters into the "PROGRAM_STATE_VAR" category:
429	  */
430	 return src_reg(PROGRAM_STATE_VAR, idx);
431   }
432
433   idx = _mesa_add_unnamed_constant( paramList, values );
434
435   return src_reg(PROGRAM_STATE_VAR, idx);
436}
437
438
439
440/***********************************************************************
441 * Expand various instructions here to simpler forms.
442 */
443static void precalc_dst( struct brw_wm_compile *c,
444			       const struct prog_instruction *inst )
445{
446   struct prog_src_register src0 = inst->SrcReg[0];
447   struct prog_src_register src1 = inst->SrcReg[1];
448   struct prog_dst_register dst = inst->DstReg;
449
450   if (dst.WriteMask & WRITEMASK_Y) {
451      /* dst.y = mul src0.y, src1.y
452       */
453      emit_op(c,
454	      OPCODE_MUL,
455	      dst_mask(dst, WRITEMASK_Y),
456	      inst->SaturateMode, 0, 0,
457	      src0,
458	      src1,
459	      src_undef());
460   }
461
462
463   if (dst.WriteMask & WRITEMASK_XZ) {
464      GLuint z = GET_SWZ(src0.Swizzle, Z);
465
466      /* dst.xz = swz src0.1zzz
467       */
468      emit_op(c,
469	      OPCODE_SWZ,
470	      dst_mask(dst, WRITEMASK_XZ),
471	      inst->SaturateMode, 0, 0,
472	      src_swizzle(src0, SWIZZLE_ONE, z, z, z),
473	      src_undef(),
474	      src_undef());
475   }
476   if (dst.WriteMask & WRITEMASK_W) {
477      /* dst.w = mov src1.w
478       */
479      emit_op(c,
480	      OPCODE_MOV,
481	      dst_mask(dst, WRITEMASK_W),
482	      inst->SaturateMode, 0, 0,
483	      src1,
484	      src_undef(),
485	      src_undef());
486   }
487}
488
489
490static void precalc_lit( struct brw_wm_compile *c,
491			 const struct prog_instruction *inst )
492{
493   struct prog_src_register src0 = inst->SrcReg[0];
494   struct prog_dst_register dst = inst->DstReg;
495
496   if (dst.WriteMask & WRITEMASK_XW) {
497      /* dst.xw = swz src0.1111
498       */
499      emit_op(c,
500	      OPCODE_SWZ,
501	      dst_mask(dst, WRITEMASK_XW),
502	      0, 0, 0,
503	      src_swizzle1(src0, SWIZZLE_ONE),
504	      src_undef(),
505	      src_undef());
506   }
507
508
509   if (dst.WriteMask & WRITEMASK_YZ) {
510      emit_op(c,
511	      OPCODE_LIT,
512	      dst_mask(dst, WRITEMASK_YZ),
513	      inst->SaturateMode, 0, 0,
514	      src0,
515	      src_undef(),
516	      src_undef());
517   }
518}
519
520static void precalc_tex( struct brw_wm_compile *c,
521			 const struct prog_instruction *inst )
522{
523   /* Need to emit YUV texture conversions by hand.  Probably need to
524    * do this here - the alternative is in brw_wm_emit.c, but the
525    * conversion requires allocating a temporary variable which we
526    * don't have the facility to do that late in the compilation.
527    */
528   if (!(c->key.yuvtex_mask & (1<<inst->TexSrcUnit))) {
529      emit_op(c,
530	      OPCODE_TEX,
531	      inst->DstReg,
532	      inst->SaturateMode,
533	      inst->TexSrcUnit,
534	      inst->TexSrcTarget,
535	      inst->SrcReg[0],
536	      src_undef(),
537	      src_undef());
538   }
539   else {
540      /*
541	 CONST C0 = { -.5, -.0625,  -.5, 1.164 }
542	 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
543	 UYV     = TEX ...
544	 UYV.xyz = ADD UYV,     C0
545	 UYV.y   = MUL UYV.y,   C0.w
546	 RGB.xyz = MAD UYV.xxz, C1,   UYV.y
547	 RGB.y   = MAD UYV.z,   C1.w, RGB.y
548      */
549      struct prog_dst_register dst = inst->DstReg;
550      struct prog_src_register src0 = inst->SrcReg[0];
551      struct prog_dst_register tmp = get_temp(c);
552      struct prog_src_register tmpsrc = src_reg_from_dst(tmp);
553      struct prog_src_register C0 = search_or_add_const4f( c,  -.5, -.0625, -.5, 1.164 );
554      struct prog_src_register C1 = search_or_add_const4f( c, 1.596, -0.813, 2.018, -.391 );
555
556      /* tmp     = TEX ...
557       */
558      emit_op(c,
559	      OPCODE_TEX,
560	      tmp,
561	      inst->SaturateMode,
562	      inst->TexSrcUnit,
563	      inst->TexSrcTarget,
564	      src0,
565	      src_undef(),
566	      src_undef());
567
568      /* tmp.xyz =  ADD TMP, C0
569       */
570      emit_op(c,
571	      OPCODE_ADD,
572	      dst_mask(tmp, WRITEMASK_XYZ),
573	      0, 0, 0,
574	      tmpsrc,
575	      C0,
576	      src_undef());
577
578      /* YUV.y   = MUL YUV.y, C0.w
579       */
580      emit_op(c,
581	      OPCODE_MUL,
582	      dst_mask(tmp, WRITEMASK_Y),
583	      0, 0, 0,
584	      tmpsrc,
585	      src_swizzle1(C0, W),
586	      src_undef());
587
588      /* RGB.xyz = MAD YUV.xxz, C1, YUV.y
589       */
590      emit_op(c,
591	      OPCODE_MAD,
592	      dst_mask(dst, WRITEMASK_XYZ),
593	      0, 0, 0,
594	      src_swizzle(tmpsrc, X,X,Z,Z),
595	      C1,
596	      src_swizzle1(tmpsrc, Y));
597
598      /*  RGB.y   = MAD YUV.z, C1.w, RGB.y
599       */
600      emit_op(c,
601	      OPCODE_MAD,
602	      dst_mask(dst, WRITEMASK_Y),
603	      0, 0, 0,
604	      src_swizzle1(tmpsrc, Z),
605	      src_swizzle1(C1, W),
606	      src_swizzle1(src_reg_from_dst(dst), Y));
607   }
608}
609
610
611static GLboolean projtex( struct brw_wm_compile *c,
612			  const struct prog_instruction *inst )
613{
614   struct prog_src_register src = inst->SrcReg[0];
615
616   /* Only try to detect the simplest cases.  Could detect (later)
617    * cases where we are trying to emit code like RCP {1.0}, MUL x,
618    * {1.0}, and so on.
619    *
620    * More complex cases than this typically only arise from
621    * user-provided fragment programs anyway:
622    */
623   if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX)
624      return 0;  /* ut2004 gun rendering !?! */
625   else if (src.File == PROGRAM_INPUT &&
626	    GET_SWZ(src.Swizzle, W) == W &&
627	    (c->key.projtex_mask & (1<<src.Index)) == 0)
628      return 0;
629   else
630      return 1;
631}
632
633
634static void precalc_txp( struct brw_wm_compile *c,
635			       const struct prog_instruction *inst )
636{
637   struct prog_src_register src0 = inst->SrcReg[0];
638
639   if (projtex(c, inst)) {
640      struct prog_dst_register tmp = get_temp(c);
641      struct prog_instruction tmp_inst;
642
643      /* tmp0.w = RCP inst.arg[0][3]
644       */
645      emit_op(c,
646	      OPCODE_RCP,
647	      dst_mask(tmp, WRITEMASK_W),
648	      0, 0, 0,
649	      src_swizzle1(src0, GET_SWZ(src0.Swizzle, W)),
650	      src_undef(),
651	      src_undef());
652
653      /* tmp0.xyz =  MUL inst.arg[0], tmp0.wwww
654       */
655      emit_op(c,
656	      OPCODE_MUL,
657	      dst_mask(tmp, WRITEMASK_XYZ),
658	      0, 0, 0,
659	      src0,
660	      src_swizzle1(src_reg_from_dst(tmp), W),
661	      src_undef());
662
663      /* dst = precalc(TEX tmp0)
664       */
665      tmp_inst = *inst;
666      tmp_inst.SrcReg[0] = src_reg_from_dst(tmp);
667      precalc_tex(c, &tmp_inst);
668
669      release_temp(c, tmp);
670   }
671   else
672   {
673      /* dst = precalc(TEX src0)
674       */
675      precalc_tex(c, inst);
676   }
677}
678
679
680
681
682
683/***********************************************************************
684 * Add instructions to perform fog blending
685 */
686
687static void fog_blend( struct brw_wm_compile *c,
688			     struct prog_src_register fog_factor )
689{
690   struct prog_dst_register outcolor = dst_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
691   struct prog_src_register fogcolor = search_or_add_param6( c, STATE_FOG_COLOR, 0,0,0,0,0 );
692
693   /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
694
695   emit_op(c,
696	   OPCODE_LRP,
697	   dst_mask(outcolor, WRITEMASK_XYZ),
698	   0, 0, 0,
699	   fog_factor,
700	   src_reg_from_dst(outcolor),
701	   fogcolor);
702}
703
704
705
706/* This one is simple - just take the interpolated fog coordinate and
707 * use it as the fog blend factor.
708 */
709static void fog_interpolated( struct brw_wm_compile *c )
710{
711   struct prog_src_register fogc = src_reg(PROGRAM_INPUT, FRAG_ATTRIB_FOGC);
712
713   if (!(c->fp_interp_emitted & (1<<FRAG_ATTRIB_FOGC)))
714      emit_interp(c, FRAG_ATTRIB_FOGC);
715
716   fog_blend( c, src_swizzle1(fogc, GET_SWZ(fogc.Swizzle,X)));
717}
718
719static void emit_fog( struct brw_wm_compile *c )
720{
721   if (!c->fp->program.FogOption)
722      return;
723
724   if (1)
725      fog_interpolated( c );
726   else {
727      /* TODO: per-pixel fog */
728      assert(0);
729   }
730}
731
732static void emit_fb_write( struct brw_wm_compile *c )
733{
734   struct prog_src_register outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
735   struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
736   struct prog_src_register outdepth = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DEPR);
737
738   emit_op(c,
739	   WM_FB_WRITE,
740	   dst_mask(dst_undef(),0),
741	   0, 0, 0,
742	   outcolor,
743	   payload_r0_depth,
744	   outdepth);
745}
746
747
748
749
750/***********************************************************************
751 * Emit INTERP instructions ahead of first use of each attrib.
752 */
753
754static void validate_src_regs( struct brw_wm_compile *c,
755			       const struct prog_instruction *inst )
756{
757   GLuint nr_args = brw_wm_nr_args( inst->Opcode );
758   GLuint i;
759
760   for (i = 0; i < nr_args; i++) {
761      if (inst->SrcReg[i].File == PROGRAM_INPUT) {
762	 GLuint idx = inst->SrcReg[i].Index;
763	 if (!(c->fp_interp_emitted & (1<<idx))) {
764	    emit_interp(c, idx);
765	 }
766      }
767   }
768}
769
770
771
772void brw_wm_pass_fp( struct brw_wm_compile *c )
773{
774   struct brw_fragment_program *fp = c->fp;
775   GLuint insn;
776
777   if (INTEL_DEBUG & DEBUG_WM) {
778      _mesa_printf("\n\n\npre-fp:\n");
779/*       _mesa_print_program(&fp->program); */
780      _mesa_printf("\n");
781   }
782
783   c->pixel_xy = src_undef();
784   c->delta_xy = src_undef();
785   c->pixel_w = src_undef();
786   c->nr_fp_insns = 0;
787
788   /* Emit preamble instructions:
789    */
790
791
792   for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
793      const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
794      struct prog_instruction *out;
795
796      /* Check for INPUT values, emit INTERP instructions where
797       * necessary:
798       */
799      validate_src_regs(c, inst);
800
801
802      switch (inst->Opcode) {
803      case OPCODE_SWZ:
804	 out = emit_insn(c, inst);
805	 out->Opcode = OPCODE_MOV;
806	 break;
807
808      case OPCODE_ABS:
809	 out = emit_insn(c, inst);
810	 out->Opcode = OPCODE_MOV;
811	 out->SrcReg[0].NegateBase = 0;
812	 out->SrcReg[0].Abs = 1;
813	 break;
814
815      case OPCODE_SUB:
816	 out = emit_insn(c, inst);
817	 out->Opcode = OPCODE_ADD;
818	 out->SrcReg[1].NegateBase ^= 0xf;
819	 break;
820
821      case OPCODE_SCS:
822	 out = emit_insn(c, inst);
823	 /* This should probably be done in the parser.
824	  */
825	 out->DstReg.WriteMask &= WRITEMASK_XY;
826	 break;
827
828      case OPCODE_DST:
829	 precalc_dst(c, inst);
830	 break;
831
832      case OPCODE_LIT:
833	 precalc_lit(c, inst);
834	 break;
835
836      case OPCODE_TXP:
837	 precalc_txp(c, inst);
838	 break;
839
840      case OPCODE_XPD:
841	 out = emit_insn(c, inst);
842	 /* This should probably be done in the parser.
843	  */
844	 out->DstReg.WriteMask &= WRITEMASK_XYZ;
845	 break;
846
847      case OPCODE_KIL:
848	 out = emit_insn(c, inst);
849	 /* This should probably be done in the parser.
850	  */
851	 out->DstReg.WriteMask = 0;
852	 break;
853
854      case OPCODE_END:
855      case OPCODE_PRINT:
856	 break;
857
858      default:
859	 emit_insn(c, inst);
860	 break;
861      }
862   }
863
864   emit_fog(c);
865   emit_fb_write(c);
866
867
868   if (INTEL_DEBUG & DEBUG_WM) {
869      _mesa_printf("\n\n\npass_fp:\n");
870/*       _mesa_debug_fp_inst(c->nr_fp_insns, c->prog_instructions, wm_opcode_strings, wm_file_strings);  */
871      _mesa_printf("\n");
872   }
873}
874
875