i965: rewrite the code for handling shader subroutine calls
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_fp.c
index 7f7b957cbe892bfde9c390c55f4ecc44e4780d38..8b5ccdba931983983d7f45b5ef9380c1145d5cb9 100644 (file)
@@ -111,6 +111,12 @@ static struct prog_src_register src_swizzle1( struct prog_src_register reg, int
    return src_swizzle(reg, x, x, x, x);
 }
 
+static struct prog_src_register src_swizzle4( struct prog_src_register reg, uint swizzle )
+{
+   reg.Swizzle = swizzle;
+   return reg;
+}
+
 
 /***********************************************************************
  * Dest regs
@@ -122,10 +128,11 @@ static struct prog_dst_register dst_reg(GLuint file, GLuint idx)
    reg.File = file;
    reg.Index = idx;
    reg.WriteMask = WRITEMASK_XYZW;
+   reg.RelAddr = 0;
    reg.CondMask = 0;
    reg.CondSwizzle = 0;
-   reg.pad = 0;
    reg.CondSrc = 0;
+   reg.pad = 0;
    return reg;
 }
 
@@ -176,7 +183,6 @@ static struct prog_instruction *emit_insn(struct brw_wm_compile *c,
 {
    struct prog_instruction *inst = get_fp_inst(c);
    *inst = *inst0;
-   inst->Data = (void *)inst0;
    return inst;
 }
 
@@ -553,12 +559,19 @@ static void precalc_lit( struct brw_wm_compile *c,
    }
 }
 
+
+/**
+ * Some TEX instructions require extra code, cube map coordinate
+ * normalization, or coordinate scaling for RECT textures, etc.
+ * This function emits those extra instructions and the TEX
+ * instruction itself.
+ */
 static void precalc_tex( struct brw_wm_compile *c,
                         const struct prog_instruction *inst )
 {
    struct prog_src_register coord;
    struct prog_dst_register tmpcoord;
-   GLuint unit = c->fp->program.Base.SamplerUnits[inst->TexSrcUnit];
+   const GLuint unit = c->fp->program.Base.SamplerUnits[inst->TexSrcUnit];
 
    if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX) {
        struct prog_instruction *out;
@@ -568,9 +581,11 @@ static void precalc_tex( struct brw_wm_compile *c,
        struct prog_src_register tmp1src = src_reg_from_dst(tmp1);
        struct prog_src_register src0 = inst->SrcReg[0];
 
+       /* find longest component of coord vector and normalize it */
        tmpcoord = get_temp(c);
        coord = src_reg_from_dst(tmpcoord);
 
+       /* tmpcoord = src0 (i.e.: coord = src0) */
        out = emit_op(c, OPCODE_MOV,
                      tmpcoord,
                      0, 0, 0,
@@ -580,6 +595,7 @@ static void precalc_tex( struct brw_wm_compile *c,
        out->SrcReg[0].NegateBase = 0;
        out->SrcReg[0].Abs = 1;
 
+       /* tmp0 = MAX(coord.X, coord.Y) */
        emit_op(c, OPCODE_MAX,
                tmp0,
                0, 0, 0,
@@ -587,6 +603,7 @@ static void precalc_tex( struct brw_wm_compile *c,
                src_swizzle1(coord, Y),
                src_undef());
 
+       /* tmp1 = MAX(tmp0, coord.Z) */
        emit_op(c, OPCODE_MAX,
                tmp1,
                0, 0, 0,
@@ -594,6 +611,7 @@ static void precalc_tex( struct brw_wm_compile *c,
                src_swizzle1(coord, Z),
                src_undef());
 
+       /* tmp0 = 1 / tmp1 */
        emit_op(c, OPCODE_RCP,
                tmp0,
                0, 0, 0,
@@ -601,6 +619,7 @@ static void precalc_tex( struct brw_wm_compile *c,
                src_undef(),
                src_undef());
 
+       /* tmpCoord = src0 * tmp0 */
        emit_op(c, OPCODE_MUL,
                tmpcoord,
                0, 0, 0,
@@ -610,7 +629,8 @@ static void precalc_tex( struct brw_wm_compile *c,
 
        release_temp(c, tmp0);
        release_temp(c, tmp1);
-   } else if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
+   }
+   else if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
       struct prog_src_register scale = 
         search_or_add_param5( c, 
                               STATE_INTERNAL, 
@@ -641,19 +661,9 @@ static void precalc_tex( struct brw_wm_compile *c,
     * conversion requires allocating a temporary variable which we
     * don't have the facility to do that late in the compilation.
     */
-   if (!(c->key.yuvtex_mask & (1<<unit))) {
-      emit_op(c, 
-             OPCODE_TEX,
-             inst->DstReg,
-             inst->SaturateMode,
-             unit,
-             inst->TexSrcTarget,
-             coord,
-             src_undef(),
-             src_undef());
-   }
-   else {
-       GLboolean  swap_uv = c->key.yuvtex_swap_mask & (1<<unit);
+   if (c->key.yuvtex_mask & (1 << unit)) {
+      /* convert ycbcr to RGBA */
+      GLboolean  swap_uv = c->key.yuvtex_swap_mask & (1<<unit);
 
       /* 
         CONST C0 = { -.5, -.0625,  -.5, 1.164 }
@@ -733,6 +743,31 @@ static void precalc_tex( struct brw_wm_compile *c,
 
       release_temp(c, tmp);
    }
+   else {
+      /* ordinary RGBA tex instruction */
+      emit_op(c, 
+             OPCODE_TEX,
+             inst->DstReg,
+             inst->SaturateMode,
+             unit,
+             inst->TexSrcTarget,
+             coord,
+             src_undef(),
+             src_undef());
+   }
+
+   /* For GL_EXT_texture_swizzle: */
+   if (c->key.tex_swizzles[unit] != SWIZZLE_NOOP) {
+      /* swizzle the result of the TEX instruction */
+      struct prog_src_register tmpsrc = src_reg_from_dst(inst->DstReg);
+      emit_op(c, OPCODE_SWZ,
+              inst->DstReg,
+              SATURATE_OFF, /* saturate already done above */
+              0, 0,   /* tex unit, target N/A */
+              src_swizzle4(tmpsrc, c->key.tex_swizzles[unit]),
+              src_undef(),
+              src_undef());
+   }
 
    if ((inst->TexSrcTarget == TEXTURE_RECT_INDEX) ||
        (inst->TexSrcTarget == TEXTURE_CUBE_INDEX))
@@ -810,62 +845,11 @@ static void precalc_txp( struct brw_wm_compile *c,
 
 
 
-
-
-/***********************************************************************
- * Add instructions to perform fog blending
- */
-
-static void fog_blend( struct brw_wm_compile *c,
-                            struct prog_src_register fog_factor )
-{
-   struct prog_dst_register outcolor = dst_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
-   struct prog_src_register fogcolor = search_or_add_param5( c, STATE_FOG_COLOR, 0,0,0,0 );
-
-   /* color.xyz = LRP fog_factor.xxxx, output_color, fog_color */
-   
-   emit_op(c, 
-          OPCODE_LRP,
-          dst_mask(outcolor, WRITEMASK_XYZ),
-          0, 0, 0,
-          fog_factor,
-          src_reg_from_dst(outcolor),
-          fogcolor);
-}
-
-
-
-/* This one is simple - just take the interpolated fog coordinate and
- * use it as the fog blend factor.
- */
-static void fog_interpolated( struct brw_wm_compile *c )
-{
-   struct prog_src_register fogc = src_reg(PROGRAM_INPUT, FRAG_ATTRIB_FOGC);
-   
-   if (!(c->fp_interp_emitted & (1<<FRAG_ATTRIB_FOGC))) 
-      emit_interp(c, FRAG_ATTRIB_FOGC);
-
-   fog_blend( c, src_swizzle1(fogc, GET_SWZ(fogc.Swizzle,X)));
-}
-
-static void emit_fog( struct brw_wm_compile *c ) 
-{
-   if (!c->fp->program.FogOption)
-      return;
-
-   if (1) 
-      fog_interpolated( c );
-   else {
-      /* TODO: per-pixel fog */
-      assert(0);
-   }
-}
-
 static void emit_fb_write( struct brw_wm_compile *c )
 {
-   struct prog_src_register outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
    struct prog_src_register payload_r0_depth = src_reg(PROGRAM_PAYLOAD, PAYLOAD_DEPTH);
    struct prog_src_register outdepth = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DEPR);
+   struct prog_src_register outcolor;
    GLuint i;
 
    struct prog_instruction *inst, *last_inst;
@@ -889,7 +873,14 @@ static void emit_fb_write( struct brw_wm_compile *c )
           }
        }
        last_inst->Sampler |= 1; //eot
-   }else {
+   }
+   else {
+      /* if gl_FragData[0] is written, use it, else use gl_FragColor */
+      if (c->fp->program.Base.OutputsWritten & (1 << FRAG_RESULT_DATA0))
+         outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DATA0);
+      else 
+         outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
+
        inst = emit_op(c, WM_FB_WRITE, dst_mask(dst_undef(),0),
               0, 0, 0, outcolor, payload_r0_depth, outdepth);
        inst->Sampler = 1|(0<<1);
@@ -950,13 +941,18 @@ static void print_insns( const struct prog_instruction *insn,
    }
 }
 
+
+/**
+ * Initial pass for fragment program code generation.
+ * This function is used by both the GLSL and non-GLSL paths.
+ */
 void brw_wm_pass_fp( struct brw_wm_compile *c )
 {
    struct brw_fragment_program *fp = c->fp;
    GLuint insn;
 
    if (INTEL_DEBUG & DEBUG_WM) {
-      _mesa_printf("\n\n\npre-fp:\n");
+      _mesa_printf("pre-fp:\n");
       _mesa_print_program(&fp->program.Base); 
       _mesa_printf("\n");
    }
@@ -966,15 +962,19 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
    c->pixel_w = src_undef();
    c->nr_fp_insns = 0;
 
-   /* Emit preamble instructions:
+   /* Emit preamble instructions.  This is where special instructions such as
+    * WM_CINTERP, WM_LINTERP, WM_PINTERP and WM_WPOSXY are emitted to
+    * compute shader inputs from varying vars.
     */
-
-
    for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
       const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
       validate_src_regs(c, inst);
       validate_dst_regs(c, inst);
    }
+
+   /* Loop over all instructions doing assorted simplifications and
+    * transformations.
+    */
    for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
       const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
       struct prog_instruction *out;
@@ -983,7 +983,6 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
        * necessary:
        */
 
-
       switch (inst->Opcode) {
       case OPCODE_SWZ: 
         out = emit_insn(c, inst);
@@ -1051,7 +1050,6 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
          emit_ddy(c, inst);
        break;
       case OPCODE_END:
-        emit_fog(c);
         emit_fb_write(c);
         break;
       case OPCODE_PRINT:
@@ -1064,7 +1062,7 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
    }
 
    if (INTEL_DEBUG & DEBUG_WM) {
-          _mesa_printf("\n\n\npass_fp:\n");
+          _mesa_printf("pass_fp:\n");
           print_insns( c->prog_instructions, c->nr_fp_insns );
           _mesa_printf("\n");
    }