brw_wm_fp.c revision 7676980d38cff417015bca8d23549d567d74228b
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   inst->Data = (void *)inst0;
180   return inst;
181}
182
183static struct prog_instruction * emit_op(struct brw_wm_compile *c,
184				       GLuint op,
185				       struct prog_dst_register dest,
186				       GLuint saturate,
187				       GLuint tex_src_unit,
188				       GLuint tex_src_target,
189				       struct prog_src_register src0,
190				       struct prog_src_register src1,
191				       struct prog_src_register src2 )
192{
193   struct prog_instruction *inst = get_fp_inst(c);
194
195   memset(inst, 0, sizeof(*inst));
196
197   inst->Opcode = op;
198   inst->DstReg = dest;
199   inst->SaturateMode = saturate;
200   inst->TexSrcUnit = tex_src_unit;
201   inst->TexSrcTarget = tex_src_target;
202   inst->SrcReg[0] = src0;
203   inst->SrcReg[1] = src1;
204   inst->SrcReg[2] = src2;
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
364static void emit_ddx( struct brw_wm_compile *c,
365        const struct prog_instruction *inst )
366{
367    GLuint idx = inst->SrcReg[0].Index;
368    struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
369
370    c->fp_deriv_emitted |= 1<<idx;
371    emit_op(c,
372            OPCODE_DDX,
373            inst->DstReg,
374            0, 0, 0,
375            interp,
376            get_pixel_w(c),
377            src_undef());
378}
379
380static void emit_ddy( struct brw_wm_compile *c,
381        const struct prog_instruction *inst )
382{
383    GLuint idx = inst->SrcReg[0].Index;
384    struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
385
386    c->fp_deriv_emitted |= 1<<idx;
387    emit_op(c,
388            OPCODE_DDY,
389            inst->DstReg,
390            0, 0, 0,
391            interp,
392            get_pixel_w(c),
393            src_undef());
394}
395
396/***********************************************************************
397 * Hacks to extend the program parameter and constant lists.
398 */
399
400/* Add the fog parameters to the parameter list of the original
401 * program, rather than creating a new list.  Doesn't really do any
402 * harm and it's not as if the parameter handling isn't a big hack
403 * anyway.
404 */
405static struct prog_src_register search_or_add_param5(struct brw_wm_compile *c,
406                                                     GLint s0,
407                                                     GLint s1,
408                                                     GLint s2,
409                                                     GLint s3,
410                                                     GLint s4)
411{
412   struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
413   gl_state_index tokens[STATE_LENGTH];
414   GLuint idx;
415   tokens[0] = s0;
416   tokens[1] = s1;
417   tokens[2] = s2;
418   tokens[3] = s3;
419   tokens[4] = s4;
420
421   for (idx = 0; idx < paramList->NumParameters; idx++) {
422      if (paramList->Parameters[idx].Type == PROGRAM_STATE_VAR &&
423	  memcmp(paramList->Parameters[idx].StateIndexes, tokens, sizeof(tokens)) == 0)
424	 return src_reg(PROGRAM_STATE_VAR, idx);
425   }
426
427   idx = _mesa_add_state_reference( paramList, tokens );
428
429   /* Recalculate state dependency:
430    */
431   c->fp->param_state = paramList->StateFlags;
432
433   return src_reg(PROGRAM_STATE_VAR, idx);
434}
435
436
437static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
438						     GLfloat s0,
439						     GLfloat s1,
440						     GLfloat s2,
441						     GLfloat s3)
442{
443   struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
444   GLfloat values[4];
445   GLuint idx;
446   GLuint swizzle;
447
448   values[0] = s0;
449   values[1] = s1;
450   values[2] = s2;
451   values[3] = s3;
452
453   /* Have to search, otherwise multiple compilations will each grow
454    * the parameter list.
455    */
456   for (idx = 0; idx < paramList->NumParameters; idx++) {
457      if (paramList->Parameters[idx].Type == PROGRAM_CONSTANT &&
458	  memcmp(paramList->ParameterValues[idx], values, sizeof(values)) == 0)
459
460	 /* XXX: this mimics the mesa bug which puts all constants and
461	  * parameters into the "PROGRAM_STATE_VAR" category:
462	  */
463	 return src_reg(PROGRAM_STATE_VAR, idx);
464   }
465
466   idx = _mesa_add_unnamed_constant( paramList, values, 4, &swizzle );
467   assert(swizzle == SWIZZLE_NOOP); /* Need to handle swizzle in reg setup */
468   return src_reg(PROGRAM_STATE_VAR, idx);
469}
470
471
472
473/***********************************************************************
474 * Expand various instructions here to simpler forms.
475 */
476static void precalc_dst( struct brw_wm_compile *c,
477			       const struct prog_instruction *inst )
478{
479   struct prog_src_register src0 = inst->SrcReg[0];
480   struct prog_src_register src1 = inst->SrcReg[1];
481   struct prog_dst_register dst = inst->DstReg;
482
483   if (dst.WriteMask & WRITEMASK_Y) {
484      /* dst.y = mul src0.y, src1.y
485       */
486      emit_op(c,
487	      OPCODE_MUL,
488	      dst_mask(dst, WRITEMASK_Y),
489	      inst->SaturateMode, 0, 0,
490	      src0,
491	      src1,
492	      src_undef());
493   }
494
495
496   if (dst.WriteMask & WRITEMASK_XZ) {
497      GLuint z = GET_SWZ(src0.Swizzle, Z);
498
499      /* dst.xz = swz src0.1zzz
500       */
501      emit_op(c,
502	      OPCODE_SWZ,
503	      dst_mask(dst, WRITEMASK_XZ),
504	      inst->SaturateMode, 0, 0,
505	      src_swizzle(src0, SWIZZLE_ONE, z, z, z),
506	      src_undef(),
507	      src_undef());
508   }
509   if (dst.WriteMask & WRITEMASK_W) {
510      /* dst.w = mov src1.w
511       */
512      emit_op(c,
513	      OPCODE_MOV,
514	      dst_mask(dst, WRITEMASK_W),
515	      inst->SaturateMode, 0, 0,
516	      src1,
517	      src_undef(),
518	      src_undef());
519   }
520}
521
522
523static void precalc_lit( struct brw_wm_compile *c,
524			 const struct prog_instruction *inst )
525{
526   struct prog_src_register src0 = inst->SrcReg[0];
527   struct prog_dst_register dst = inst->DstReg;
528
529   if (dst.WriteMask & WRITEMASK_XW) {
530      /* dst.xw = swz src0.1111
531       */
532      emit_op(c,
533	      OPCODE_SWZ,
534	      dst_mask(dst, WRITEMASK_XW),
535	      0, 0, 0,
536	      src_swizzle1(src0, SWIZZLE_ONE),
537	      src_undef(),
538	      src_undef());
539   }
540
541
542   if (dst.WriteMask & WRITEMASK_YZ) {
543      emit_op(c,
544	      OPCODE_LIT,
545	      dst_mask(dst, WRITEMASK_YZ),
546	      inst->SaturateMode, 0, 0,
547	      src0,
548	      src_undef(),
549	      src_undef());
550   }
551}
552
553static void precalc_tex( struct brw_wm_compile *c,
554			 const struct prog_instruction *inst )
555{
556   struct prog_src_register coord;
557   struct prog_dst_register tmpcoord;
558
559   if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX) {
560       struct prog_instruction *out;
561       struct prog_dst_register tmp0 = get_temp(c);
562       struct prog_src_register tmp0src = src_reg_from_dst(tmp0);
563       struct prog_dst_register tmp1 = get_temp(c);
564       struct prog_src_register tmp1src = src_reg_from_dst(tmp1);
565       struct prog_src_register src0 = inst->SrcReg[0];
566
567       tmpcoord = get_temp(c);
568       coord = src_reg_from_dst(tmpcoord);
569
570       out = emit_op(c, OPCODE_MOV,
571                     tmpcoord,
572                     0, 0, 0,
573                     src0,
574                     src_undef(),
575                     src_undef());
576       out->SrcReg[0].NegateBase = 0;
577       out->SrcReg[0].Abs = 1;
578
579       emit_op(c, OPCODE_MAX,
580               tmp0,
581               0, 0, 0,
582               src_swizzle1(coord, X),
583               src_swizzle1(coord, Y),
584               src_undef());
585
586       emit_op(c, OPCODE_MAX,
587               tmp1,
588               0, 0, 0,
589               tmp0src,
590               src_swizzle1(coord, Z),
591               src_undef());
592
593       emit_op(c, OPCODE_RCP,
594               tmp0,
595               0, 0, 0,
596               tmp1src,
597               src_undef(),
598               src_undef());
599
600       emit_op(c, OPCODE_MUL,
601               tmpcoord,
602               0, 0, 0,
603               src0,
604               tmp0src,
605               src_undef());
606
607       release_temp(c, tmp0);
608       release_temp(c, tmp1);
609   } else if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
610      struct prog_src_register scale =
611	 search_or_add_param5( c,
612			       STATE_INTERNAL,
613			       STATE_TEXRECT_SCALE,
614			       inst->TexSrcUnit,
615			       0,0 );
616
617      tmpcoord = get_temp(c);
618
619      /* coord.xy   = MUL inst->SrcReg[0], { 1/width, 1/height }
620       */
621      emit_op(c,
622	      OPCODE_MUL,
623	      tmpcoord,
624	      0, 0, 0,
625	      inst->SrcReg[0],
626	      scale,
627	      src_undef());
628
629      coord = src_reg_from_dst(tmpcoord);
630   }
631   else {
632      coord = inst->SrcReg[0];
633   }
634
635   /* Need to emit YUV texture conversions by hand.  Probably need to
636    * do this here - the alternative is in brw_wm_emit.c, but the
637    * conversion requires allocating a temporary variable which we
638    * don't have the facility to do that late in the compilation.
639    */
640   if (!(c->key.yuvtex_mask & (1<<inst->TexSrcUnit))) {
641      emit_op(c,
642	      OPCODE_TEX,
643	      inst->DstReg,
644	      inst->SaturateMode,
645	      inst->TexSrcUnit,
646	      inst->TexSrcTarget,
647	      coord,
648	      src_undef(),
649	      src_undef());
650   }
651   else {
652       GLboolean  swap_uv = c->key.yuvtex_swap_mask & (1<<inst->TexSrcUnit);
653
654      /*
655	 CONST C0 = { -.5, -.0625,  -.5, 1.164 }
656	 CONST C1 = { 1.596, -0.813, 2.018, -.391 }
657	 UYV     = TEX ...
658	 UYV.xyz = ADD UYV,     C0
659	 UYV.y   = MUL UYV.y,   C0.w
660 	 if (UV swaped)
661	    RGB.xyz = MAD UYV.zzx, C1,   UYV.y
662	 else
663	    RGB.xyz = MAD UYV.xxz, C1,   UYV.y
664	 RGB.y   = MAD UYV.z,   C1.w, RGB.y
665      */
666      struct prog_dst_register dst = inst->DstReg;
667      struct prog_dst_register tmp = get_temp(c);
668      struct prog_src_register tmpsrc = src_reg_from_dst(tmp);
669      struct prog_src_register C0 = search_or_add_const4f( c,  -.5, -.0625, -.5, 1.164 );
670      struct prog_src_register C1 = search_or_add_const4f( c, 1.596, -0.813, 2.018, -.391 );
671
672      /* tmp     = TEX ...
673       */
674      emit_op(c,
675	      OPCODE_TEX,
676	      tmp,
677	      inst->SaturateMode,
678	      inst->TexSrcUnit,
679	      inst->TexSrcTarget,
680	      coord,
681	      src_undef(),
682	      src_undef());
683
684      /* tmp.xyz =  ADD TMP, C0
685       */
686      emit_op(c,
687	      OPCODE_ADD,
688	      dst_mask(tmp, WRITEMASK_XYZ),
689	      0, 0, 0,
690	      tmpsrc,
691	      C0,
692	      src_undef());
693
694      /* YUV.y   = MUL YUV.y, C0.w
695       */
696
697      emit_op(c,
698	      OPCODE_MUL,
699	      dst_mask(tmp, WRITEMASK_Y),
700	      0, 0, 0,
701	      tmpsrc,
702	      src_swizzle1(C0, W),
703	      src_undef());
704
705      /*
706       * if (UV swaped)
707       *     RGB.xyz = MAD YUV.zzx, C1, YUV.y
708       * else
709       *     RGB.xyz = MAD YUV.xxz, C1, YUV.y
710       */
711
712      emit_op(c,
713	      OPCODE_MAD,
714	      dst_mask(dst, WRITEMASK_XYZ),
715	      0, 0, 0,
716	      swap_uv?src_swizzle(tmpsrc, Z,Z,X,X):src_swizzle(tmpsrc, X,X,Z,Z),
717	      C1,
718	      src_swizzle1(tmpsrc, Y));
719
720      /*  RGB.y   = MAD YUV.z, C1.w, RGB.y
721       */
722      emit_op(c,
723	      OPCODE_MAD,
724	      dst_mask(dst, WRITEMASK_Y),
725	      0, 0, 0,
726	      src_swizzle1(tmpsrc, Z),
727	      src_swizzle1(C1, W),
728	      src_swizzle1(src_reg_from_dst(dst), Y));
729
730      release_temp(c, tmp);
731   }
732
733   if (inst->TexSrcTarget == GL_TEXTURE_RECTANGLE_NV)
734      release_temp(c, tmpcoord);
735}
736
737
738static GLboolean projtex( struct brw_wm_compile *c,
739			  const struct prog_instruction *inst )
740{
741   struct prog_src_register src = inst->SrcReg[0];
742
743   /* Only try to detect the simplest cases.  Could detect (later)
744    * cases where we are trying to emit code like RCP {1.0}, MUL x,
745    * {1.0}, and so on.
746    *
747    * More complex cases than this typically only arise from
748    * user-provided fragment programs anyway:
749    */
750   if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX)
751      return 0;  /* ut2004 gun rendering !?! */
752   else if (src.File == PROGRAM_INPUT &&
753	    GET_SWZ(src.Swizzle, W) == W &&
754           (c->key.projtex_mask & (1<<(src.Index + FRAG_ATTRIB_WPOS - FRAG_ATTRIB_TEX0))) == 0)
755      return 0;
756   else
757      return 1;
758}
759
760
761static void precalc_txp( struct brw_wm_compile *c,
762			       const struct prog_instruction *inst )
763{
764   struct prog_src_register src0 = inst->SrcReg[0];
765
766   if (projtex(c, inst)) {
767      struct prog_dst_register tmp = get_temp(c);
768      struct prog_instruction tmp_inst;
769
770      /* tmp0.w = RCP inst.arg[0][3]
771       */
772      emit_op(c,
773	      OPCODE_RCP,
774	      dst_mask(tmp, WRITEMASK_W),
775	      0, 0, 0,
776	      src_swizzle1(src0, GET_SWZ(src0.Swizzle, W)),
777	      src_undef(),
778	      src_undef());
779
780      /* tmp0.xyz =  MUL inst.arg[0], tmp0.wwww
781       */
782      emit_op(c,
783	      OPCODE_MUL,
784	      dst_mask(tmp, WRITEMASK_XYZ),
785	      0, 0, 0,
786	      src0,
787	      src_swizzle1(src_reg_from_dst(tmp), W),
788	      src_undef());
789
790      /* dst = precalc(TEX tmp0)
791       */
792      tmp_inst = *inst;
793      tmp_inst.SrcReg[0] = src_reg_from_dst(tmp);
794      precalc_tex(c, &tmp_inst);
795
796      release_temp(c, tmp);
797   }
798   else
799   {
800      /* dst = precalc(TEX src0)
801       */
802      precalc_tex(c, inst);
803   }
804}
805
806
807
808
809
810/***********************************************************************
811 * Add instructions to perform fog blending
812 */
813
814static void fog_blend( struct brw_wm_compile *c,
815			     struct prog_src_register fog_factor )
816{
817   struct prog_dst_register outcolor = dst_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
818   struct prog_src_register fogcolor = search_or_add_param5( c, STATE_FOG_COLOR, 0,0,0,0 );
819
820   /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
821
822   emit_op(c,
823	   OPCODE_LRP,
824	   dst_mask(outcolor, WRITEMASK_XYZ),
825	   0, 0, 0,
826	   fog_factor,
827	   src_reg_from_dst(outcolor),
828	   fogcolor);
829}
830
831
832
833/* This one is simple - just take the interpolated fog coordinate and
834 * use it as the fog blend factor.
835 */
836static void fog_interpolated( struct brw_wm_compile *c )
837{
838   struct prog_src_register fogc = src_reg(PROGRAM_INPUT, FRAG_ATTRIB_FOGC);
839
840   if (!(c->fp_interp_emitted & (1<<FRAG_ATTRIB_FOGC)))
841      emit_interp(c, FRAG_ATTRIB_FOGC);
842
843   fog_blend( c, src_swizzle1(fogc, GET_SWZ(fogc.Swizzle,X)));
844}
845
846static void emit_fog( struct brw_wm_compile *c )
847{
848   if (!c->fp->program.FogOption)
849      return;
850
851   if (1)
852      fog_interpolated( c );
853   else {
854      /* TODO: per-pixel fog */
855      assert(0);
856   }
857}
858
859static void emit_fb_write( struct brw_wm_compile *c )
860{
861   struct prog_src_register outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
862   struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
863   struct prog_src_register outdepth = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DEPR);
864
865   emit_op(c,
866	   WM_FB_WRITE,
867	   dst_mask(dst_undef(),0),
868	   0, 0, 0,
869	   outcolor,
870	   payload_r0_depth,
871	   outdepth);
872}
873
874
875
876
877/***********************************************************************
878 * Emit INTERP instructions ahead of first use of each attrib.
879 */
880
881static void validate_src_regs( struct brw_wm_compile *c,
882			       const struct prog_instruction *inst )
883{
884   GLuint nr_args = brw_wm_nr_args( inst->Opcode );
885   GLuint i;
886
887   for (i = 0; i < nr_args; i++) {
888      if (inst->SrcReg[i].File == PROGRAM_INPUT) {
889	 GLuint idx = inst->SrcReg[i].Index;
890	 if (!(c->fp_interp_emitted & (1<<idx))) {
891	    emit_interp(c, idx);
892	 }
893      }
894   }
895}
896
897
898
899static void print_insns( const struct prog_instruction *insn,
900			 GLuint nr )
901{
902   GLuint i;
903   for (i = 0; i < nr; i++, insn++) {
904      _mesa_printf("%3d: ", i);
905      if (insn->Opcode < MAX_OPCODE)
906	 _mesa_print_instruction(insn);
907      else if (insn->Opcode < MAX_WM_OPCODE) {
908	 GLuint idx = insn->Opcode - MAX_OPCODE;
909
910	 _mesa_print_alu_instruction(insn,
911				     wm_opcode_strings[idx],
912				     3);
913      }
914      else
915	 _mesa_printf("UNKNOWN\n");
916
917   }
918}
919
920void brw_wm_pass_fp( struct brw_wm_compile *c )
921{
922   struct brw_fragment_program *fp = c->fp;
923   GLuint insn;
924
925   if (INTEL_DEBUG & DEBUG_WM) {
926      _mesa_printf("\n\n\npre-fp:\n");
927      _mesa_print_program(&fp->program.Base);
928      _mesa_printf("\n");
929   }
930
931   c->pixel_xy = src_undef();
932   c->delta_xy = src_undef();
933   c->pixel_w = src_undef();
934   c->nr_fp_insns = 0;
935
936   /* Emit preamble instructions:
937    */
938
939
940   for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
941      const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
942      struct prog_instruction *out;
943
944      /* Check for INPUT values, emit INTERP instructions where
945       * necessary:
946       */
947      validate_src_regs(c, inst);
948
949
950      switch (inst->Opcode) {
951      case OPCODE_SWZ:
952	 out = emit_insn(c, inst);
953	 out->Opcode = OPCODE_MOV;
954	 break;
955
956      case OPCODE_ABS:
957	 out = emit_insn(c, inst);
958	 out->Opcode = OPCODE_MOV;
959	 out->SrcReg[0].NegateBase = 0;
960	 out->SrcReg[0].Abs = 1;
961	 break;
962
963      case OPCODE_SUB:
964	 out = emit_insn(c, inst);
965	 out->Opcode = OPCODE_ADD;
966	 out->SrcReg[1].NegateBase ^= 0xf;
967	 break;
968
969      case OPCODE_SCS:
970	 out = emit_insn(c, inst);
971	 /* This should probably be done in the parser.
972	  */
973	 out->DstReg.WriteMask &= WRITEMASK_XY;
974	 break;
975
976      case OPCODE_DST:
977	 precalc_dst(c, inst);
978	 break;
979
980      case OPCODE_LIT:
981	 precalc_lit(c, inst);
982	 break;
983
984      case OPCODE_TXP:
985	 precalc_txp(c, inst);
986	 break;
987
988      case OPCODE_XPD:
989	 out = emit_insn(c, inst);
990	 /* This should probably be done in the parser.
991	  */
992	 out->DstReg.WriteMask &= WRITEMASK_XYZ;
993	 break;
994
995      case OPCODE_KIL:
996	 out = emit_insn(c, inst);
997	 /* This should probably be done in the parser.
998	  */
999	 out->DstReg.WriteMask = 0;
1000	 break;
1001      case OPCODE_DDX:
1002	 emit_ddx(c, inst);
1003	 break;
1004      case OPCODE_DDY:
1005         emit_ddy(c, inst);
1006	break;
1007      case OPCODE_END:
1008	 emit_fog(c);
1009	 emit_fb_write(c);
1010	 break;
1011      case OPCODE_PRINT:
1012	 break;
1013
1014      default:
1015	 emit_insn(c, inst);
1016	 break;
1017      }
1018   }
1019
1020   if (INTEL_DEBUG & DEBUG_WM) {
1021	   _mesa_printf("\n\n\npass_fp:\n");
1022	   print_insns( c->prog_instructions, c->nr_fp_insns );
1023	   _mesa_printf("\n");
1024   }
1025}
1026
1027