brw_wm_fp.c revision e7b0ec9ae79d4ec4aba402b9124fde55d914da92
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
63#if 0
64static const char *wm_file_strings[] = {
65   "PAYLOAD"
66};
67#endif
68
69
70/***********************************************************************
71 * Source regs
72 */
73
74static struct prog_src_register src_reg(GLuint file, GLuint idx)
75{
76   struct prog_src_register reg;
77   reg.File = file;
78   reg.Index = idx;
79   reg.Swizzle = SWIZZLE_NOOP;
80   reg.RelAddr = 0;
81   reg.NegateBase = 0;
82   reg.Abs = 0;
83   reg.NegateAbs = 0;
84   return reg;
85}
86
87static struct prog_src_register src_reg_from_dst(struct prog_dst_register dst)
88{
89   return src_reg(dst.File, dst.Index);
90}
91
92static struct prog_src_register src_undef( void )
93{
94   return src_reg(PROGRAM_UNDEFINED, 0);
95}
96
97static GLboolean src_is_undef(struct prog_src_register src)
98{
99   return src.File == PROGRAM_UNDEFINED;
100}
101
102static struct prog_src_register src_swizzle( struct prog_src_register reg, int x, int y, int z, int w )
103{
104   reg.Swizzle = MAKE_SWIZZLE4(x,y,z,w);
105   return reg;
106}
107
108static struct prog_src_register src_swizzle1( struct prog_src_register reg, int x )
109{
110   return src_swizzle(reg, x, x, x, x);
111}
112
113
114/***********************************************************************
115 * Dest regs
116 */
117
118static struct prog_dst_register dst_reg(GLuint file, GLuint idx)
119{
120   struct prog_dst_register reg;
121   reg.File = file;
122   reg.Index = idx;
123   reg.WriteMask = WRITEMASK_XYZW;
124   reg.CondMask = 0;
125   reg.CondSwizzle = 0;
126   reg.pad = 0;
127   reg.CondSrc = 0;
128   return reg;
129}
130
131static struct prog_dst_register dst_mask( struct prog_dst_register reg, int mask )
132{
133   reg.WriteMask &= mask;
134   return reg;
135}
136
137static struct prog_dst_register dst_undef( void )
138{
139   return dst_reg(PROGRAM_UNDEFINED, 0);
140}
141
142
143
144static struct prog_dst_register get_temp( struct brw_wm_compile *c )
145{
146   int bit = ffs( ~c->fp_temp );
147
148   if (!bit) {
149      _mesa_printf("%s: out of temporaries\n", __FILE__);
150      exit(1);
151   }
152
153   c->fp_temp |= 1<<(bit-1);
154   return dst_reg(PROGRAM_TEMPORARY, FIRST_INTERNAL_TEMP+(bit-1));
155}
156
157
158static void release_temp( struct brw_wm_compile *c, struct prog_dst_register temp )
159{
160   c->fp_temp &= ~1<<(temp.Index + 1 - FIRST_INTERNAL_TEMP);
161}
162
163
164/***********************************************************************
165 * Instructions
166 */
167
168static struct prog_instruction *get_fp_inst(struct brw_wm_compile *c)
169{
170   return &c->prog_instructions[c->nr_fp_insns++];
171}
172
173static struct prog_instruction *emit_insn(struct brw_wm_compile *c,
174					const struct prog_instruction *inst0)
175{
176   struct prog_instruction *inst = get_fp_inst(c);
177   *inst = *inst0;
178   return inst;
179}
180
181static struct prog_instruction * emit_op(struct brw_wm_compile *c,
182				       GLuint op,
183				       struct prog_dst_register dest,
184				       GLuint saturate,
185				       GLuint tex_src_unit,
186				       GLuint tex_src_target,
187				       struct prog_src_register src0,
188				       struct prog_src_register src1,
189				       struct prog_src_register src2 )
190{
191   struct prog_instruction *inst = get_fp_inst(c);
192
193   memset(inst, 0, sizeof(*inst));
194
195   inst->Opcode = op;
196   inst->DstReg = dest;
197   inst->SaturateMode = saturate;
198   inst->TexSrcUnit = tex_src_unit;
199   inst->TexSrcTarget = tex_src_target;
200   inst->SrcReg[0] = src0;
201   inst->SrcReg[1] = src1;
202   inst->SrcReg[2] = src2;
203
204   return inst;
205}
206
207
208
209
210/***********************************************************************
211 * Special instructions for interpolation and other tasks
212 */
213
214static struct prog_src_register get_pixel_xy( struct brw_wm_compile *c )
215{
216   if (src_is_undef(c->pixel_xy)) {
217      struct prog_dst_register pixel_xy = get_temp(c);
218      struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
219
220
221      /* Emit the out calculations, and hold onto the results.  Use
222       * two instructions as a temporary is required.
223       */
224      /* pixel_xy.xy = PIXELXY payload[0];
225       */
226      emit_op(c,
227	      WM_PIXELXY,
228	      dst_mask(pixel_xy, WRITEMASK_XY),
229	      0, 0, 0,
230	      payload_r0_depth,
231	      src_undef(),
232	      src_undef());
233
234      c->pixel_xy = src_reg_from_dst(pixel_xy);
235   }
236
237   return c->pixel_xy;
238}
239
240static struct prog_src_register get_delta_xy( struct brw_wm_compile *c )
241{
242   if (src_is_undef(c->delta_xy)) {
243      struct prog_dst_register delta_xy = get_temp(c);
244      struct prog_src_register pixel_xy = get_pixel_xy(c);
245      struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
246
247      /* deltas.xy = DELTAXY pixel_xy, payload[0]
248       */
249      emit_op(c,
250	      WM_DELTAXY,
251	      dst_mask(delta_xy, WRITEMASK_XY),
252	      0, 0, 0,
253	      pixel_xy,
254	      payload_r0_depth,
255	      src_undef());
256
257      c->delta_xy = src_reg_from_dst(delta_xy);
258   }
259
260   return c->delta_xy;
261}
262
263static struct prog_src_register get_pixel_w( struct brw_wm_compile *c )
264{
265   if (src_is_undef(c->pixel_w)) {
266      struct prog_dst_register pixel_w = get_temp(c);
267      struct prog_src_register deltas = get_delta_xy(c);
268      struct prog_src_register interp_wpos = src_reg(PROGRAM_PAYLOAD, FRAG_ATTRIB_WPOS);
269
270
271      /* deltas.xyw = DELTAS2 deltas.xy, payload.interp_wpos.x
272       */
273      emit_op(c,
274	      WM_PIXELW,
275	      dst_mask(pixel_w, WRITEMASK_W),
276	      0, 0, 0,
277	      interp_wpos,
278	      deltas,
279	      src_undef());
280
281
282      c->pixel_w = src_reg_from_dst(pixel_w);
283   }
284
285   return c->pixel_w;
286}
287
288static void emit_interp( struct brw_wm_compile *c,
289			 GLuint idx )
290{
291   struct prog_dst_register dst = dst_reg(PROGRAM_INPUT, idx);
292   struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
293   struct prog_src_register deltas = get_delta_xy(c);
294   struct prog_src_register arg2;
295   GLuint opcode;
296
297   /* Need to use PINTERP on attributes which have been
298    * multiplied by 1/W in the SF program, and LINTERP on those
299    * which have not:
300    */
301   switch (idx) {
302   case FRAG_ATTRIB_WPOS:
303      opcode = WM_LINTERP;
304      arg2 = src_undef();
305
306      /* Have to treat wpos.xy specially:
307       */
308      emit_op(c,
309	      WM_WPOSXY,
310	      dst_mask(dst, WRITEMASK_XY),
311	      0, 0, 0,
312	      get_pixel_xy(c),
313	      src_undef(),
314	      src_undef());
315
316      dst = dst_mask(dst, WRITEMASK_ZW);
317
318      /* PROGRAM_INPUT.attr.xyzw = INTERP payload.interp[attr].x, deltas.xyw
319       */
320      emit_op(c,
321	      WM_LINTERP,
322	      dst,
323	      0, 0, 0,
324	      interp,
325	      deltas,
326	      arg2);
327      break;
328   case FRAG_ATTRIB_COL0:
329   case FRAG_ATTRIB_COL1:
330      if (c->key.flat_shade) {
331	 emit_op(c,
332		 WM_CINTERP,
333		 dst,
334		 0, 0, 0,
335		 interp,
336		 src_undef(),
337		 src_undef());
338      }
339      else {
340	 emit_op(c,
341		 WM_LINTERP,
342		 dst,
343		 0, 0, 0,
344		 interp,
345		 deltas,
346		 src_undef());
347      }
348      break;
349   default:
350      emit_op(c,
351	      WM_PINTERP,
352	      dst,
353	      0, 0, 0,
354	      interp,
355	      deltas,
356	      get_pixel_w(c));
357      break;
358   }
359
360   c->fp_interp_emitted |= 1<<idx;
361}
362
363
364/***********************************************************************
365 * Hacks to extend the program parameter and constant lists.
366 */
367
368/* Add the fog parameters to the parameter list of the original
369 * program, rather than creating a new list.  Doesn't really do any
370 * harm and it's not as if the parameter handling isn't a big hack
371 * anyway.
372 */
373static struct prog_src_register search_or_add_param6( struct brw_wm_compile *c,
374					     GLint s0,
375					     GLint s1,
376					     GLint s2,
377					     GLint s3,
378					     GLint s4,
379					     GLint s5)
380{
381   struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
382   GLint tokens[6];
383   GLuint idx;
384   tokens[0] = s0;
385   tokens[1] = s1;
386   tokens[2] = s2;
387   tokens[3] = s3;
388   tokens[4] = s4;
389   tokens[5] = s5;
390
391   for (idx = 0; idx < paramList->NumParameters; idx++) {
392      if (paramList->Parameters[idx].Type == PROGRAM_STATE_VAR &&
393	  memcmp(paramList->Parameters[idx].StateIndexes, tokens, sizeof(tokens)) == 0)
394	 return src_reg(PROGRAM_STATE_VAR, idx);
395   }
396
397   idx = _mesa_add_state_reference( paramList, tokens );
398
399   /* Recalculate state dependency:
400    */
401   c->fp->param_state = brw_parameter_list_state_flags( paramList );
402
403   return src_reg(PROGRAM_STATE_VAR, idx);
404}
405
406
407static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
408						     GLfloat s0,
409						     GLfloat s1,
410						     GLfloat s2,
411						     GLfloat s3)
412{
413   struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
414   GLfloat values[4];
415   GLuint idx;
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 );
436
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_param6( c,
531			       STATE_INTERNAL,
532			       STATE_TEXRECT_SCALE,
533			       inst->TexSrcUnit,
534			       0,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)) == 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_param6( c, STATE_FOG_COLOR, 0,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