i965: Fix failure to upload new constant data when changing programs.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_fp.c
index ba2dbeccde2165eaa5d8760d42b428b07e9dfe30..7f7b957cbe892bfde9c390c55f4ecc44e4780d38 100644 (file)
   */
                
 
-#include "glheader.h"
-#include "macros.h"
-#include "enums.h"
+#include "main/glheader.h"
+#include "main/macros.h"
+#include "main/enums.h"
 #include "brw_context.h"
 #include "brw_wm.h"
 #include "brw_util.h"
 
-#include "shader/program.h"
-#include "shader/program_instruction.h"
-#include "shader/arbprogparse.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_print.h"
+#include "shader/prog_statevars.h"
+
 
 #define FIRST_INTERNAL_TEMP MAX_NV_FRAGMENT_PROGRAM_TEMPS
 
@@ -143,7 +144,7 @@ static struct prog_dst_register dst_undef( void )
 
 static struct prog_dst_register get_temp( struct brw_wm_compile *c )
 {
-   int bit = ffs( ~c->fp_temp );
+   int bit = _mesa_ffs( ~c->fp_temp );
 
    if (!bit) {
       _mesa_printf("%s: out of temporaries\n", __FILE__);
@@ -157,7 +158,7 @@ static struct prog_dst_register get_temp( struct brw_wm_compile *c )
 
 static void release_temp( struct brw_wm_compile *c, struct prog_dst_register temp )
 {
-   c->fp_temp &= ~1<<(temp.Index + 1 - FIRST_INTERNAL_TEMP);
+   c->fp_temp &= ~(1 << (temp.Index - FIRST_INTERNAL_TEMP));
 }
 
 
@@ -175,6 +176,7 @@ 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;
 }
 
@@ -200,7 +202,6 @@ static struct prog_instruction * emit_op(struct brw_wm_compile *c,
    inst->SrcReg[0] = src0;
    inst->SrcReg[1] = src1;
    inst->SrcReg[2] = src2;
-   
    return inst;
 }
    
@@ -360,6 +361,37 @@ static void emit_interp( struct brw_wm_compile *c,
    c->fp_interp_emitted |= 1<<idx;
 }
 
+static void emit_ddx( struct brw_wm_compile *c,
+        const struct prog_instruction *inst )
+{
+    GLuint idx = inst->SrcReg[0].Index;
+    struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
+
+    c->fp_deriv_emitted |= 1<<idx;
+    emit_op(c,
+            OPCODE_DDX,
+            inst->DstReg,
+            0, 0, 0,
+            interp,
+            get_pixel_w(c),
+            src_undef());
+}
+
+static void emit_ddy( struct brw_wm_compile *c,
+        const struct prog_instruction *inst )
+{
+    GLuint idx = inst->SrcReg[0].Index;
+    struct prog_src_register interp = src_reg(PROGRAM_PAYLOAD, idx);
+
+    c->fp_deriv_emitted |= 1<<idx;
+    emit_op(c,
+            OPCODE_DDY,
+            inst->DstReg,
+            0, 0, 0,
+            interp,
+            get_pixel_w(c),
+            src_undef());
+}
 
 /***********************************************************************
  * Hacks to extend the program parameter and constant lists.
@@ -370,23 +402,21 @@ static void emit_interp( struct brw_wm_compile *c,
  * harm and it's not as if the parameter handling isn't a big hack
  * anyway.
  */
-static struct prog_src_register search_or_add_param6( struct brw_wm_compile *c, 
-                                            GLint s0,
-                                            GLint s1,
-                                            GLint s2,
-                                            GLint s3,
-                                            GLint s4,
-                                            GLint s5)
+static struct prog_src_register search_or_add_param5(struct brw_wm_compile *c, 
+                                                     GLint s0,
+                                                     GLint s1,
+                                                     GLint s2,
+                                                     GLint s3,
+                                                     GLint s4)
 {
    struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
-   GLint tokens[6];
+   gl_state_index tokens[STATE_LENGTH];
    GLuint idx;
    tokens[0] = s0;
    tokens[1] = s1;
    tokens[2] = s2;
    tokens[3] = s3;
    tokens[4] = s4;
-   tokens[5] = s5;
    
    for (idx = 0; idx < paramList->NumParameters; idx++) {
       if (paramList->Parameters[idx].Type == PROGRAM_STATE_VAR &&
@@ -396,10 +426,6 @@ static struct prog_src_register search_or_add_param6( struct brw_wm_compile *c,
 
    idx = _mesa_add_state_reference( paramList, tokens );
 
-   /* Recalculate state dependency: 
-    */
-   c->fp->param_state = paramList->StateFlags;
-
    return src_reg(PROGRAM_STATE_VAR, idx);
 }
 
@@ -413,6 +439,7 @@ static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
    struct gl_program_parameter_list *paramList = c->fp->program.Base.Parameters;
    GLfloat values[4];
    GLuint idx;
+   GLuint swizzle;
 
    values[0] = s0;
    values[1] = s1;
@@ -432,8 +459,8 @@ static struct prog_src_register search_or_add_const4f( struct brw_wm_compile *c,
         return src_reg(PROGRAM_STATE_VAR, idx);
    }
    
-   idx = _mesa_add_unnamed_constant( paramList, values, 4 );
-
+   idx = _mesa_add_unnamed_constant( paramList, values, 4, &swizzle );
+   assert(swizzle == SWIZZLE_NOOP); /* Need to handle swizzle in reg setup */
    return src_reg(PROGRAM_STATE_VAR, idx);
 }
 
@@ -463,17 +490,20 @@ static void precalc_dst( struct brw_wm_compile *c,
 
 
    if (dst.WriteMask & WRITEMASK_XZ) {
+      struct prog_instruction *swz;
       GLuint z = GET_SWZ(src0.Swizzle, Z);
 
       /* dst.xz = swz src0.1zzz
        */
-      emit_op(c,
-             OPCODE_SWZ,
-             dst_mask(dst, WRITEMASK_XZ),
-             inst->SaturateMode, 0, 0,
-             src_swizzle(src0, SWIZZLE_ONE, z, z, z),
-             src_undef(),
-             src_undef());
+      swz = emit_op(c,
+                   OPCODE_SWZ,
+                   dst_mask(dst, WRITEMASK_XZ),
+                   inst->SaturateMode, 0, 0,
+                   src_swizzle(src0, SWIZZLE_ONE, z, z, z),
+                   src_undef(),
+                   src_undef());
+      /* Avoid letting negation flag of src0 affect our 1 constant. */
+      swz->SrcReg[0].NegateBase &= ~NEGATE_X;
    }
    if (dst.WriteMask & WRITEMASK_W) {
       /* dst.w = mov src1.w
@@ -496,15 +526,19 @@ static void precalc_lit( struct brw_wm_compile *c,
    struct prog_dst_register dst = inst->DstReg;
    
    if (dst.WriteMask & WRITEMASK_XW) {
+      struct prog_instruction *swz;
+
       /* dst.xw = swz src0.1111
        */
-      emit_op(c,
-             OPCODE_SWZ,
-             dst_mask(dst, WRITEMASK_XW),
-             0, 0, 0,
-             src_swizzle1(src0, SWIZZLE_ONE),
-             src_undef(),
-             src_undef());
+      swz = emit_op(c,
+                   OPCODE_SWZ,
+                   dst_mask(dst, WRITEMASK_XW),
+                   0, 0, 0,
+                   src_swizzle1(src0, SWIZZLE_ONE),
+                   src_undef(),
+                   src_undef());
+      /* Avoid letting the negation flag of src0 affect our 1 constant. */
+      swz->SrcReg[0].NegateBase = 0;
    }
 
 
@@ -524,14 +558,65 @@ static void precalc_tex( struct brw_wm_compile *c,
 {
    struct prog_src_register coord;
    struct prog_dst_register tmpcoord;
-
-   if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
+   GLuint unit = c->fp->program.Base.SamplerUnits[inst->TexSrcUnit];
+
+   if (inst->TexSrcTarget == TEXTURE_CUBE_INDEX) {
+       struct prog_instruction *out;
+       struct prog_dst_register tmp0 = get_temp(c);
+       struct prog_src_register tmp0src = src_reg_from_dst(tmp0);
+       struct prog_dst_register tmp1 = get_temp(c);
+       struct prog_src_register tmp1src = src_reg_from_dst(tmp1);
+       struct prog_src_register src0 = inst->SrcReg[0];
+
+       tmpcoord = get_temp(c);
+       coord = src_reg_from_dst(tmpcoord);
+
+       out = emit_op(c, OPCODE_MOV,
+                     tmpcoord,
+                     0, 0, 0,
+                     src0,
+                     src_undef(),
+                     src_undef());
+       out->SrcReg[0].NegateBase = 0;
+       out->SrcReg[0].Abs = 1;
+
+       emit_op(c, OPCODE_MAX,
+               tmp0,
+               0, 0, 0,
+               src_swizzle1(coord, X),
+               src_swizzle1(coord, Y),
+               src_undef());
+
+       emit_op(c, OPCODE_MAX,
+               tmp1,
+               0, 0, 0,
+               tmp0src,
+               src_swizzle1(coord, Z),
+               src_undef());
+
+       emit_op(c, OPCODE_RCP,
+               tmp0,
+               0, 0, 0,
+               tmp1src,
+               src_undef(),
+               src_undef());
+
+       emit_op(c, OPCODE_MUL,
+               tmpcoord,
+               0, 0, 0,
+               src0,
+               tmp0src,
+               src_undef());
+
+       release_temp(c, tmp0);
+       release_temp(c, tmp1);
+   } else if (inst->TexSrcTarget == TEXTURE_RECT_INDEX) {
       struct prog_src_register scale = 
-        search_or_add_param6( c, 
+        search_or_add_param5( c, 
                               STATE_INTERNAL, 
                               STATE_TEXRECT_SCALE,
-                              inst->TexSrcUnit,
-                              0,0,0 );
+                              unit,
+                              0,0 );
 
       tmpcoord = get_temp(c);
 
@@ -556,29 +641,33 @@ 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<<inst->TexSrcUnit))) {
+   if (!(c->key.yuvtex_mask & (1<<unit))) {
       emit_op(c, 
              OPCODE_TEX,
              inst->DstReg,
              inst->SaturateMode,
-             inst->TexSrcUnit,
+             unit,
              inst->TexSrcTarget,
              coord,
              src_undef(),
              src_undef());
    }
    else {
+       GLboolean  swap_uv = c->key.yuvtex_swap_mask & (1<<unit);
+
       /* 
         CONST C0 = { -.5, -.0625,  -.5, 1.164 }
         CONST C1 = { 1.596, -0.813, 2.018, -.391 }
         UYV     = TEX ...
         UYV.xyz = ADD UYV,     C0
         UYV.y   = MUL UYV.y,   C0.w
-        RGB.xyz = MAD UYV.xxz, C1,   UYV.y
+        if (UV swaped)
+           RGB.xyz = MAD UYV.zzx, C1,   UYV.y
+        else
+           RGB.xyz = MAD UYV.xxz, C1,   UYV.y 
         RGB.y   = MAD UYV.z,   C1.w, RGB.y
       */
       struct prog_dst_register dst = inst->DstReg;
-      struct prog_src_register src0 = inst->SrcReg[0];
       struct prog_dst_register tmp = get_temp(c);
       struct prog_src_register tmpsrc = src_reg_from_dst(tmp);
       struct prog_src_register C0 = search_or_add_const4f( c,  -.5, -.0625, -.5, 1.164 );
@@ -590,9 +679,9 @@ static void precalc_tex( struct brw_wm_compile *c,
              OPCODE_TEX,
              tmp,
              inst->SaturateMode,
-             inst->TexSrcUnit,
+             unit,
              inst->TexSrcTarget,
-             src0,
+             coord,
              src_undef(),
              src_undef());
 
@@ -608,6 +697,7 @@ static void precalc_tex( struct brw_wm_compile *c,
 
       /* YUV.y   = MUL YUV.y, C0.w
        */
+
       emit_op(c,
              OPCODE_MUL,
              dst_mask(tmp, WRITEMASK_Y),
@@ -616,13 +706,18 @@ static void precalc_tex( struct brw_wm_compile *c,
              src_swizzle1(C0, W),
              src_undef());
 
-      /* RGB.xyz = MAD YUV.xxz, C1, YUV.y
+      /* 
+       * if (UV swaped)
+       *     RGB.xyz = MAD YUV.zzx, C1, YUV.y
+       * else
+       *     RGB.xyz = MAD YUV.xxz, C1, YUV.y
        */
+
       emit_op(c,
              OPCODE_MAD,
              dst_mask(dst, WRITEMASK_XYZ),
              0, 0, 0,
-             src_swizzle(tmpsrc, X,X,Z,Z),
+             swap_uv?src_swizzle(tmpsrc, Z,Z,X,X):src_swizzle(tmpsrc, X,X,Z,Z),
              C1,
              src_swizzle1(tmpsrc, Y));
 
@@ -639,7 +734,8 @@ static void precalc_tex( struct brw_wm_compile *c,
       release_temp(c, tmp);
    }
 
-   if (inst->TexSrcTarget == GL_TEXTURE_RECTANGLE_NV) 
+   if ((inst->TexSrcTarget == TEXTURE_RECT_INDEX) ||
+       (inst->TexSrcTarget == TEXTURE_CUBE_INDEX))
       release_temp(c, tmpcoord);
 }
 
@@ -660,7 +756,7 @@ static GLboolean projtex( struct brw_wm_compile *c,
       return 0;  /* ut2004 gun rendering !?! */
    else if (src.File == PROGRAM_INPUT && 
            GET_SWZ(src.Swizzle, W) == W &&
-           (c->key.projtex_mask & (1<<src.Index)) == 0)
+           (c->key.projtex_mask & (1<<(src.Index + FRAG_ATTRIB_WPOS - FRAG_ATTRIB_TEX0))) == 0)
       return 0;
    else
       return 1;
@@ -724,7 +820,7 @@ 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_param6( c, STATE_FOG_COLOR, 0,0,0,0,0 );
+   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 */
    
@@ -770,14 +866,34 @@ 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);
+   GLuint i;
 
-   emit_op(c,
-          WM_FB_WRITE,
-          dst_mask(dst_undef(),0),
-          0, 0, 0,
-          outcolor,
-          payload_r0_depth,
-          outdepth);
+   struct prog_instruction *inst, *last_inst;
+   struct brw_context *brw = c->func.brw;
+
+   /* inst->Sampler is not used by backend, 
+      use it for fb write target and eot */
+
+   if (brw->state.nr_draw_regions > 1) {
+       for (i = 0 ; i < brw->state.nr_draw_regions; i++) {
+          outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_DATA0 + i);
+          last_inst = inst = emit_op(c,
+                  WM_FB_WRITE, dst_mask(dst_undef(),0), 0, 0, 0,
+                  outcolor, payload_r0_depth, outdepth);
+          inst->Sampler = (i<<1);
+          if (c->fp_fragcolor_emitted) {
+              outcolor = src_reg(PROGRAM_OUTPUT, FRAG_RESULT_COLR);
+              last_inst = inst = emit_op(c, WM_FB_WRITE, dst_mask(dst_undef(),0),
+                      0, 0, 0, outcolor, payload_r0_depth, outdepth);
+              inst->Sampler = (i<<1);
+          }
+       }
+       last_inst->Sampler |= 1; //eot
+   }else {
+       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);
+   }
 }
 
 
@@ -803,7 +919,15 @@ static void validate_src_regs( struct brw_wm_compile *c,
    }
 }
         
-
+static void validate_dst_regs( struct brw_wm_compile *c,
+                              const struct prog_instruction *inst )
+{
+   if (inst->DstReg.File == PROGRAM_OUTPUT) {
+       GLuint idx = inst->DstReg.Index;
+       if (idx == FRAG_RESULT_COLR)
+          c->fp_fragcolor_emitted = 1;
+   }
+}
 
 static void print_insns( const struct prog_instruction *insn,
                         GLuint nr )
@@ -846,6 +970,11 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
     */
 
 
+   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);
+   }
    for (insn = 0; insn < fp->program.Base.NumInstructions; insn++) {
       const struct prog_instruction *inst = &fp->program.Base.Instructions[insn];
       struct prog_instruction *out;
@@ -853,7 +982,6 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
       /* Check for INPUT values, emit INTERP instructions where
        * necessary:
        */
-      validate_src_regs(c, inst);
 
 
       switch (inst->Opcode) {
@@ -889,11 +1017,20 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
       case OPCODE_LIT:
         precalc_lit(c, inst);
         break;
-     
+
+      case OPCODE_TEX:
+        precalc_tex(c, inst);
+        break;
+
       case OPCODE_TXP:
         precalc_txp(c, inst);
         break;
 
+      case OPCODE_TXB:
+        out = emit_insn(c, inst);
+        out->TexSrcUnit = fp->program.Base.SamplerUnits[inst->TexSrcUnit];
+        break;
+
       case OPCODE_XPD: 
         out = emit_insn(c, inst);
         /* This should probably be done in the parser. 
@@ -907,8 +1044,16 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
          */
         out->DstReg.WriteMask = 0;
         break;
-
+      case OPCODE_DDX:
+        emit_ddx(c, inst);
+        break;
+      case OPCODE_DDY:
+         emit_ddy(c, inst);
+       break;
       case OPCODE_END:
+        emit_fog(c);
+        emit_fb_write(c);
+        break;
       case OPCODE_PRINT:
         break;
         
@@ -917,15 +1062,11 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
         break;
       }
    }
-   
-   emit_fog(c);
-   emit_fb_write(c);
-
 
    if (INTEL_DEBUG & DEBUG_WM) {
-      _mesa_printf("\n\n\npass_fp:\n");
-      print_insns( c->prog_instructions, c->nr_fp_insns );
-      _mesa_printf("\n");
+          _mesa_printf("\n\n\npass_fp:\n");
+          print_insns( c->prog_instructions, c->nr_fp_insns );
+          _mesa_printf("\n");
    }
 }