i965: Enable faster workaround-free math on Ivybridge.
authorKenneth Graunke <kenneth@whitecape.org>
Tue, 18 Oct 2011 19:24:47 +0000 (12:24 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Mon, 7 Nov 2011 19:03:22 +0000 (11:03 -0800)
According to the documentation, Ivybridge's math instruction works in
SIMD16 mode for the fragment shader, and no longer forbids align16 mode
for the vertex shader.

The documentation claims that SIMD16 mode isn't supported for INT DIV,
but empirical evidence shows that it works fine.  Presumably the note
is trying to warn us that the variant that returns both quotient and
remainder in (dst, dst + 1) doesn't work in SIMD16 mode since dst + 1
would be sechalf(dst), trashing half your results.  Since we don't use
that variant, we don't care and can just enable SIMD16 everywhere.

The documentation also still claims that source modifiers and
conditional modifiers aren't supported, but empirical evidence and
study of the simulator both show that they work just fine.

Goodbye workarounds.  Math just works now.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Paul Berry <stereotype441@gmail.com>
src/mesa/drivers/dri/i965/brw_eu_emit.c
src/mesa/drivers/dri/i965/brw_fs.cpp
src/mesa/drivers/dri/i965/brw_fs.h
src/mesa/drivers/dri/i965/brw_fs_emit.cpp
src/mesa/drivers/dri/i965/brw_vec4.h
src/mesa/drivers/dri/i965/brw_vec4_emit.cpp

index 7284bdc45ea4f39bdb5dde58c06f7cbfdf9e2094..dbb42f4ea76e161de0f7735d23c76df5c2ee35f8 100644 (file)
@@ -1443,11 +1443,14 @@ void brw_math( struct brw_compile *p,
       assert(src.file == BRW_GENERAL_REGISTER_FILE);
 
       assert(dest.hstride == BRW_HORIZONTAL_STRIDE_1);
-      assert(src.hstride == BRW_HORIZONTAL_STRIDE_1);
+      if (intel->gen == 6)
+        assert(src.hstride == BRW_HORIZONTAL_STRIDE_1);
 
-      /* Source modifiers are ignored for extended math instructions. */
-      assert(!src.negate);
-      assert(!src.abs);
+      /* Source modifiers are ignored for extended math instructions on Gen6. */
+      if (intel->gen == 6) {
+        assert(!src.negate);
+        assert(!src.abs);
+      }
 
       if (function == BRW_MATH_FUNCTION_INT_DIV_QUOTIENT ||
          function == BRW_MATH_FUNCTION_INT_DIV_REMAINDER ||
@@ -1507,8 +1510,10 @@ void brw_math2(struct brw_compile *p,
    assert(src1.file == BRW_GENERAL_REGISTER_FILE);
 
    assert(dest.hstride == BRW_HORIZONTAL_STRIDE_1);
-   assert(src0.hstride == BRW_HORIZONTAL_STRIDE_1);
-   assert(src1.hstride == BRW_HORIZONTAL_STRIDE_1);
+   if (intel->gen == 6) {
+      assert(src0.hstride == BRW_HORIZONTAL_STRIDE_1);
+      assert(src1.hstride == BRW_HORIZONTAL_STRIDE_1);
+   }
 
    if (function == BRW_MATH_FUNCTION_INT_DIV_QUOTIENT ||
        function == BRW_MATH_FUNCTION_INT_DIV_REMAINDER ||
@@ -1520,11 +1525,13 @@ void brw_math2(struct brw_compile *p,
       assert(src1.type == BRW_REGISTER_TYPE_F);
    }
 
-   /* Source modifiers are ignored for extended math instructions. */
-   assert(!src0.negate);
-   assert(!src0.abs);
-   assert(!src1.negate);
-   assert(!src1.abs);
+   /* Source modifiers are ignored for extended math instructions on Gen6. */
+   if (intel->gen == 6) {
+      assert(!src0.negate);
+      assert(!src0.abs);
+      assert(!src1.negate);
+      assert(!src1.abs);
+   }
 
    /* Math is the same ISA format as other opcodes, except that CondModifier
     * becomes FC[3:0] and ThreadCtrl becomes FC[5:4].
index b66febbde003311d4b0df2c6f3b767160b93a9c9..2a5f5105bd56b159f259abf0c0c2158040e088cc 100644 (file)
@@ -559,10 +559,10 @@ fs_visitor::emit_math(enum opcode opcode, fs_reg dst, fs_reg src)
     * expanding that result out, but we would need to be careful with
     * masking.
     *
-    * The hardware ignores source modifiers (negate and abs) on math
+    * Gen 6 hardware ignores source modifiers (negate and abs) on math
     * instructions, so we also move to a temp to set those up.
     */
-   if (intel->gen >= 6 && (src.file == UNIFORM ||
+   if (intel->gen == 6 && (src.file == UNIFORM ||
                           src.abs ||
                           src.negate)) {
       fs_reg expanded = fs_reg(this, glsl_type::float_type);
@@ -596,7 +596,9 @@ fs_visitor::emit_math(enum opcode opcode, fs_reg dst, fs_reg src0, fs_reg src1)
       return NULL;
    }
 
-   if (intel->gen >= 6) {
+   if (intel->gen >= 7) {
+      inst = emit(opcode, dst, src0, src1);
+   } else if (intel->gen == 6) {
       /* Can't do hstride == 0 args to gen6 math, so expand it out.
        *
        * The hardware ignores source modifiers (negate and abs) on math
index e2ad6499e9500772e110bffbdb6a44ec9f60dd30..3e4503028b1060f0cf018151fb318fe63575aec8 100644 (file)
@@ -490,6 +490,13 @@ public:
    void generate_linterp(fs_inst *inst, struct brw_reg dst,
                         struct brw_reg *src);
    void generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src);
+   void generate_math1_gen7(fs_inst *inst,
+                           struct brw_reg dst,
+                           struct brw_reg src);
+   void generate_math2_gen7(fs_inst *inst,
+                           struct brw_reg dst,
+                           struct brw_reg src0,
+                           struct brw_reg src1);
    void generate_math1_gen6(fs_inst *inst,
                            struct brw_reg dst,
                            struct brw_reg src);
index 0c14baf367d0c791e42910150d55419f32c7f864..b613fb081fc746bae5ec2276b51acc5215b7722e 100644 (file)
@@ -142,6 +142,31 @@ fs_visitor::generate_linterp(fs_inst *inst,
    }
 }
 
+void
+fs_visitor::generate_math1_gen7(fs_inst *inst,
+                               struct brw_reg dst,
+                               struct brw_reg src0)
+{
+   assert(inst->mlen == 0);
+   brw_math(p, dst,
+           brw_math_function(inst->opcode),
+           inst->saturate ? BRW_MATH_SATURATE_SATURATE
+                          : BRW_MATH_SATURATE_NONE,
+           0, src0,
+           BRW_MATH_DATA_VECTOR,
+           BRW_MATH_PRECISION_FULL);
+}
+
+void
+fs_visitor::generate_math2_gen7(fs_inst *inst,
+                               struct brw_reg dst,
+                               struct brw_reg src0,
+                               struct brw_reg src1)
+{
+   assert(inst->mlen == 0);
+   brw_math2(p, dst, brw_math_function(inst->opcode), src0, src1);
+}
+
 void
 fs_visitor::generate_math1_gen6(fs_inst *inst,
                                struct brw_reg dst,
@@ -797,7 +822,9 @@ fs_visitor::generate_code()
       case SHADER_OPCODE_LOG2:
       case SHADER_OPCODE_SIN:
       case SHADER_OPCODE_COS:
-        if (intel->gen >= 6) {
+        if (intel->gen >= 7) {
+           generate_math1_gen7(inst, dst, src[0]);
+        } else if (intel->gen == 6) {
            generate_math1_gen6(inst, dst, src[0]);
         } else {
            generate_math_gen4(inst, dst, src[0]);
@@ -807,6 +834,8 @@ fs_visitor::generate_code()
       case SHADER_OPCODE_INT_REMAINDER:
       case SHADER_OPCODE_POW:
         if (intel->gen >= 6) {
+           generate_math2_gen7(inst, dst, src[0], src[1]);
+        } else if (intel->gen == 6) {
            generate_math2_gen6(inst, dst, src[0], src[1]);
         } else {
            generate_math_gen4(inst, dst, src[0]);
index a83a6b24dbc578b659d8e733afafb1cede093e2b..93ccda9548af4cedb1fc05270ee6607c7a8813cc 100644 (file)
@@ -533,6 +533,10 @@ public:
                            struct brw_reg dst,
                            struct brw_reg src0,
                            struct brw_reg src1);
+   void generate_math2_gen7(vec4_instruction *inst,
+                           struct brw_reg dst,
+                           struct brw_reg src0,
+                           struct brw_reg src1);
 
    void generate_urb_write(vec4_instruction *inst);
    void generate_oword_dual_block_offsets(struct brw_reg m1,
index 66c3b7e13d95b1ab76bea4fb7d7a31d0a0ca315b..dc39f17614a42ac2221060dfbd88bf9374ea40fb 100644 (file)
@@ -282,6 +282,18 @@ vec4_visitor::generate_math1_gen6(vec4_instruction *inst,
    brw_set_access_mode(p, BRW_ALIGN_16);
 }
 
+void
+vec4_visitor::generate_math2_gen7(vec4_instruction *inst,
+                                 struct brw_reg dst,
+                                 struct brw_reg src0,
+                                 struct brw_reg src1)
+{
+   brw_math2(p,
+            dst,
+            brw_math_function(inst->opcode),
+            src0, src1);
+}
+
 void
 vec4_visitor::generate_math2_gen6(vec4_instruction *inst,
                                  struct brw_reg dst,
@@ -552,9 +564,10 @@ vec4_visitor::generate_vs_instruction(vec4_instruction *instruction,
    case SHADER_OPCODE_LOG2:
    case SHADER_OPCODE_SIN:
    case SHADER_OPCODE_COS:
-      if (intel->gen >= 6) {
+      if (intel->gen == 6) {
         generate_math1_gen6(inst, dst, src[0]);
       } else {
+        /* Also works for Gen7. */
         generate_math1_gen4(inst, dst, src[0]);
       }
       break;
@@ -562,7 +575,9 @@ vec4_visitor::generate_vs_instruction(vec4_instruction *instruction,
    case SHADER_OPCODE_POW:
    case SHADER_OPCODE_INT_QUOTIENT:
    case SHADER_OPCODE_INT_REMAINDER:
-      if (intel->gen >= 6) {
+      if (intel->gen >= 7) {
+        generate_math2_gen7(inst, dst, src[0], src[1]);
+      } else if (intel->gen == 6) {
         generate_math2_gen6(inst, dst, src[0], src[1]);
       } else {
         generate_math2_gen4(inst, dst, src[0], src[1]);