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