i965: Mostly fix glsl-max-varyings.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_glsl.c
index e8c2cb66ec3217c02affbfb5e8de87fff76b7f2b..575f89b17faf666d722e765516f36a007bfcf2a4 100644 (file)
@@ -1,7 +1,7 @@
 #include "main/macros.h"
-#include "shader/prog_parameter.h"
-#include "shader/prog_print.h"
-#include "shader/prog_optimize.h"
+#include "program/prog_parameter.h"
+#include "program/prog_print.h"
+#include "program/prog_optimize.h"
 #include "brw_context.h"
 #include "brw_eu.h"
 #include "brw_wm.h"
@@ -23,6 +23,9 @@ GLboolean brw_wm_is_glsl(const struct gl_fragment_program *fp)
 {
     int i;
 
+    if (INTEL_DEBUG & DEBUG_GLSL_FORCE)
+       return GL_TRUE;
+
     for (i = 0; i < fp->Base.NumInstructions; i++) {
        const struct prog_instruction *inst = &fp->Base.Instructions[i];
        switch (inst->Opcode) {
@@ -289,6 +292,7 @@ reclaim_temps(struct brw_wm_compile *c)
  */
 static void prealloc_reg(struct brw_wm_compile *c)
 {
+    struct intel_context *intel = &c->func.brw->intel;
     int i, j;
     struct brw_reg reg;
     int urb_read_length = 0;
@@ -413,6 +417,43 @@ static void prealloc_reg(struct brw_wm_compile *c)
        }
     }
 
+    for (i = 0; i < c->nr_fp_insns; i++) {
+       const struct prog_instruction *inst = &c->prog_instructions[i];
+
+       switch (inst->Opcode) {
+       case WM_DELTAXY:
+           /* Allocate WM_DELTAXY destination on G45/GM45 to an
+            * even-numbered GRF if possible so that we can use the PLN
+            * instruction.
+            */
+           if (inst->DstReg.WriteMask == WRITEMASK_XY &&
+               !c->wm_regs[inst->DstReg.File][inst->DstReg.Index][0].inited &&
+               !c->wm_regs[inst->DstReg.File][inst->DstReg.Index][1].inited &&
+               (IS_G4X(intel->intelScreen->deviceID) || intel->gen == 5)) {
+               int grf;
+
+               for (grf = c->first_free_grf & ~1;
+                    grf < BRW_WM_MAX_GRF;
+                    grf += 2)
+               {
+                   if (!c->used_grf[grf] && !c->used_grf[grf + 1]) {
+                       c->used_grf[grf] = GL_TRUE;
+                       c->used_grf[grf + 1] = GL_TRUE;
+                       c->first_free_grf = grf + 2;  /* a guess */
+
+                       set_reg(c, inst->DstReg.File, inst->DstReg.Index, 0,
+                               brw_vec8_grf(grf, 0));
+                       set_reg(c, inst->DstReg.File, inst->DstReg.Index, 1,
+                               brw_vec8_grf(grf + 1, 0));
+                       break;
+                   }
+               }
+           }
+       default:
+           break;
+       }
+    }
+
     /* An instruction may reference up to three constants.
      * They'll be found in these registers.
      * XXX alloc these on demand!
@@ -529,12 +570,35 @@ static struct brw_reg get_src_reg(struct brw_wm_compile *c,
     const GLuint nr = 1;
     const GLuint component = GET_SWZ(src->Swizzle, channel);
 
-    /* Extended swizzle terms */
-    if (component == SWIZZLE_ZERO) {
-       return brw_imm_f(0.0F);
-    }
-    else if (component == SWIZZLE_ONE) {
-       return brw_imm_f(1.0F);
+    /* Only one immediate value can be used per native opcode, and it
+     * has be in the src1 slot, so not all Mesa instructions will get
+     * to take advantage of immediate constants.
+     */
+    if (brw_wm_arg_can_be_immediate(inst->Opcode, srcRegIndex)) {
+       const struct gl_program_parameter_list *params;
+
+       params = c->fp->program.Base.Parameters;
+
+       /* Extended swizzle terms */
+       if (component == SWIZZLE_ZERO) {
+         return brw_imm_f(0.0F);
+       } else if (component == SWIZZLE_ONE) {
+         if (src->Negate)
+            return brw_imm_f(-1.0F);
+         else
+            return brw_imm_f(1.0F);
+       }
+
+       if (src->File == PROGRAM_CONSTANT) {
+         float f = params->ParameterValues[src->Index][component];
+
+         if (src->Abs)
+            f = fabs(f);
+         if (src->Negate)
+            f = -f;
+
+         return brw_imm_f(f);
+       }
     }
 
     if (c->fp->use_const_buffer &&
@@ -614,112 +678,6 @@ static void invoke_subroutine( struct brw_wm_compile *c,
     }
 }
 
-/* Workaround for using brw_wm_emit.c's emit functions, which expect
- * destination regs to be uniquely written.  Moves arguments out to
- * temporaries as necessary for instructions which use their destination as
- * a temporary.
- */
-static void
-unalias3(struct brw_wm_compile *c,
-        void (*func)(struct brw_compile *c,
-                     const struct brw_reg *dst,
-                     GLuint mask,
-                     const struct brw_reg *arg0,
-                     const struct brw_reg *arg1,
-                     const struct brw_reg *arg2),
-        const struct brw_reg *dst,
-        GLuint mask,
-        const struct brw_reg *arg0,
-        const struct brw_reg *arg1,
-        const struct brw_reg *arg2)
-{
-    struct brw_compile *p = &c->func;
-    struct brw_reg tmp_arg0[4], tmp_arg1[4], tmp_arg2[4];
-    int i, j;
-    int mark = mark_tmps(c);
-
-    for (j = 0; j < 4; j++) {
-       tmp_arg0[j] = arg0[j];
-       tmp_arg1[j] = arg1[j];
-       tmp_arg2[j] = arg2[j];
-    }
-
-    for (i = 0; i < 4; i++) {
-       if (mask & (1<<i)) {
-           for (j = 0; j < 4; j++) {
-               if (arg0[j].file == dst[i].file &&
-                   dst[i].nr == arg0[j].nr) {
-                   tmp_arg0[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg0[j], arg0[j]);
-               }
-               if (arg1[j].file == dst[i].file &&
-                   dst[i].nr == arg1[j].nr) {
-                   tmp_arg1[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg1[j], arg1[j]);
-               }
-               if (arg2[j].file == dst[i].file &&
-                   dst[i].nr == arg2[j].nr) {
-                   tmp_arg2[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg2[j], arg2[j]);
-               }
-           }
-       }
-    }
-
-    func(p, dst, mask, tmp_arg0, tmp_arg1, tmp_arg2);
-
-    release_tmps(c, mark);
-}
-
-/* Workaround for using brw_wm_emit.c's emit functions, which expect
- * destination regs to be uniquely written.  Moves arguments out to
- * temporaries as necessary for instructions which use their destination as
- * a temporary.
- */
-static void
-unalias2(struct brw_wm_compile *c,
-        void (*func)(struct brw_compile *c,
-                     const struct brw_reg *dst,
-                     GLuint mask,
-                     const struct brw_reg *arg0,
-                     const struct brw_reg *arg1),
-        const struct brw_reg *dst,
-        GLuint mask,
-        const struct brw_reg *arg0,
-        const struct brw_reg *arg1)
-{
-    struct brw_compile *p = &c->func;
-    struct brw_reg tmp_arg0[4], tmp_arg1[4];
-    int i, j;
-    int mark = mark_tmps(c);
-
-    for (j = 0; j < 4; j++) {
-       tmp_arg0[j] = arg0[j];
-       tmp_arg1[j] = arg1[j];
-    }
-
-    for (i = 0; i < 4; i++) {
-       if (mask & (1<<i)) {
-           for (j = 0; j < 4; j++) {
-               if (arg0[j].file == dst[i].file &&
-                   dst[i].nr == arg0[j].nr) {
-                   tmp_arg0[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg0[j], arg0[j]);
-               }
-               if (arg1[j].file == dst[i].file &&
-                   dst[i].nr == arg1[j].nr) {
-                   tmp_arg1[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg1[j], arg1[j]);
-               }
-           }
-       }
-    }
-
-    func(p, dst, mask, tmp_arg0, tmp_arg1);
-
-    release_tmps(c, mark);
-}
-
 static void emit_arl(struct brw_wm_compile *c,
                      const struct prog_instruction *inst)
 {
@@ -743,7 +701,7 @@ static void emit_kil(struct brw_wm_compile *c)
     struct brw_reg depth = retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UW);
     brw_push_insn_state(p);
     brw_set_mask_control(p, BRW_MASK_DISABLE);
-    brw_NOT(p, c->emit_mask_reg, brw_mask_reg(1)); //IMASK
+    brw_NOT(p, c->emit_mask_reg, brw_mask_reg(1)); /* IMASK */
     brw_AND(p, depth, c->emit_mask_reg, depth);
     brw_pop_insn_state(p);
 }
@@ -1813,19 +1771,35 @@ static void
 get_argument_regs(struct brw_wm_compile *c,
                  const struct prog_instruction *inst,
                  int index,
+                 struct brw_reg *dst,
                  struct brw_reg *regs,
                  int mask)
 {
-    int i;
+    struct brw_compile *p = &c->func;
+    int i, j;
 
     for (i = 0; i < 4; i++) {
-       if (mask & (1 << i))
+       if (mask & (1 << i)) {
            regs[i] = get_src_reg(c, inst, index, i);
+
+           /* Unalias destination registers from our sources. */
+           if (regs[i].file == BRW_GENERAL_REGISTER_FILE) {
+              for (j = 0; j < 4; j++) {
+                  if (memcmp(&regs[i], &dst[j], sizeof(regs[0])) == 0) {
+                      struct brw_reg tmp = alloc_tmp(c);
+                      brw_MOV(p, tmp, regs[i]);
+                      regs[i] = tmp;
+                      break;
+                  }
+              }
+           }
+       }
     }
 }
 
 static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
 {
+   struct intel_context *intel = &brw->intel;
 #define MAX_IF_DEPTH 32
 #define MAX_LOOP_DEPTH 32
     struct brw_instruction *if_inst[MAX_IF_DEPTH], *loop_inst[MAX_LOOP_DEPTH];
@@ -1844,11 +1818,12 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
        int dst_flags;
        struct brw_reg args[3][4], dst[4];
        int j;
+       int mark = mark_tmps( c );
 
         c->cur_inst = i;
 
 #if 0
-        _mesa_printf("Inst %d: ", i);
+        printf("Inst %d: ", i);
         _mesa_print_instruction(inst);
 #endif
 
@@ -1865,7 +1840,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
           }
        }
        for (j = 0; j < brw_wm_nr_args(inst->Opcode); j++)
-           get_argument_regs(c, inst, j, args[j], WRITEMASK_XYZW);
+           get_argument_regs(c, inst, j, dst, args[j], WRITEMASK_XYZW);
 
        dst_flags = inst->DstReg.WriteMask;
        if (inst->SaturateMode == SATURATE_ZERO_ONE)
@@ -1876,10 +1851,6 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
        else
            brw_set_conditionalmod(p, BRW_CONDITIONAL_NONE);
 
-       dst_flags = inst->DstReg.WriteMask;
-       if (inst->SaturateMode == SATURATE_ZERO_ONE)
-           dst_flags |= SATURATE;
-
        switch (inst->Opcode) {
            case WM_PIXELXY:
                emit_pixel_xy(c, dst, dst_flags);
@@ -1923,8 +1894,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                emit_alu1(p, brw_RNDD, dst, dst_flags, args[0]);
                break;
            case OPCODE_LRP:
-               unalias3(c, emit_lrp,
-                        dst, dst_flags, args[0], args[1], args[2]);
+               emit_lrp(p, dst, dst_flags, args[0], args[1], args[2]);
                break;
            case OPCODE_TRUNC:
                emit_alu1(p, brw_RNDZ, dst, dst_flags, args[0]);
@@ -1963,11 +1933,14 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
            case OPCODE_LG2:
                emit_math1(c, BRW_MATH_FUNCTION_LOG, dst, dst_flags, args[0]);
                break;
+           case OPCODE_CMP:
+               emit_cmp(p, dst, dst_flags, args[0], args[1], args[2]);
+               break;
            case OPCODE_MIN:    
-               unalias2(c, emit_min, dst, dst_flags, args[0], args[1]);
+               emit_min(p, dst, dst_flags, args[0], args[1]);
                break;
            case OPCODE_MAX:    
-               unalias2(c, emit_max, dst, dst_flags, args[0], args[1]);
+               emit_max(p, dst, dst_flags, args[0], args[1]);
                break;
            case OPCODE_DDX:
            case OPCODE_DDY:
@@ -2043,6 +2016,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                if_inst[if_depth++] = brw_IF(p, BRW_EXECUTE_8);
                break;
            case OPCODE_ELSE:
+               assert(if_depth > 0);
                if_inst[if_depth-1]  = brw_ELSE(p, if_inst[if_depth-1]);
                break;
            case OPCODE_ENDIF:
@@ -2096,19 +2070,22 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                   struct brw_instruction *inst0, *inst1;
                   GLuint br = 1;
 
-                  if (BRW_IS_IGDNG(brw))
+                  if (intel->gen == 5)
                      br = 2;
+
+                 assert(loop_depth > 0);
                   loop_depth--;
                   inst0 = inst1 = brw_WHILE(p, loop_inst[loop_depth]);
                   /* patch all the BREAK/CONT instructions from last BGNLOOP */
                   while (inst0 > loop_inst[loop_depth]) {
                      inst0--;
-                     if (inst0->header.opcode == BRW_OPCODE_BREAK) {
+                     if (inst0->header.opcode == BRW_OPCODE_BREAK &&
+                        inst0->bits3.if_else.jump_count == 0) {
                        inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1);
                        inst0->bits3.if_else.pop_count = 0;
                      }
-                     else if (inst0->header.opcode == BRW_OPCODE_CONTINUE) {
+                     else if (inst0->header.opcode == BRW_OPCODE_CONTINUE &&
+                             inst0->bits3.if_else.jump_count == 0) {
                         inst0->bits3.if_else.jump_count = br * (inst1 - inst0);
                         inst0->bits3.if_else.pop_count = 0;
                      }
@@ -2116,10 +2093,14 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                }
                break;
            default:
-               _mesa_printf("unsupported IR in fragment shader %d\n",
-                       inst->Opcode);
+               printf("unsupported opcode %d (%s) in fragment shader\n",
+                      inst->Opcode, inst->Opcode < MAX_OPCODE ?
+                      _mesa_opcode_string(inst->Opcode) : "unknown");
        }
 
+       /* Release temporaries containing any unaliased source regs. */
+       release_tmps( c, mark );
+
        if (inst->CondUpdate)
            brw_set_predicate_control(p, BRW_PREDICATE_NORMAL);
        else
@@ -2128,10 +2109,10 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
     post_wm_emit(c);
 
     if (INTEL_DEBUG & DEBUG_WM) {
-      _mesa_printf("wm-native:\n");
+      printf("wm-native:\n");
       for (i = 0; i < p->nr_insn; i++)
-        brw_disasm(stderr, &p->store[i]);
-      _mesa_printf("\n");
+        brw_disasm(stderr, &p->store[i], intel->gen);
+      printf("\n");
     }
 }
 
@@ -2142,7 +2123,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
 void brw_wm_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c)
 {
     if (INTEL_DEBUG & DEBUG_WM) {
-        _mesa_printf("brw_wm_glsl_emit:\n");
+        printf("brw_wm_glsl_emit:\n");
     }
 
     /* initial instruction translation/simplification */