gallium/util: remove p_format.h from u_debug.h
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_util.c
index 4dee1be9e8cb2f89976708c33fab09cd8136fb7a..ebbd561f7d09d0bd598d97903012e1ed0232e261 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 VMware, Inc.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #include "util/u_debug.h"
 #include "pipe/p_shader_tokens.h"
+#include "tgsi_info.h"
 #include "tgsi_parse.h"
-#include "tgsi_build.h"
 #include "tgsi_util.h"
+#include "tgsi_exec.h"
+#include "util/bitscan.h"
 
 union pointer_hack
 {
@@ -38,8 +40,7 @@ union pointer_hack
 };
 
 void *
-tgsi_align_128bit(
-   void *unaligned )
+tgsi_align_128bit(void *unaligned)
 {
    union pointer_hack ph;
 
@@ -50,21 +51,20 @@ tgsi_align_128bit(
 }
 
 unsigned
-tgsi_util_get_src_register_swizzle(
-   const struct tgsi_src_register *reg,
-   unsigned component )
+tgsi_util_get_src_register_swizzle(const struct tgsi_src_register *reg,
+                                   unsigned component)
 {
-   switch( component ) {
-   case 0:
+   switch (component) {
+   case TGSI_CHAN_X:
       return reg->SwizzleX;
-   case 1:
+   case TGSI_CHAN_Y:
       return reg->SwizzleY;
-   case 2:
+   case TGSI_CHAN_Z:
       return reg->SwizzleZ;
-   case 3:
+   case TGSI_CHAN_W:
       return reg->SwizzleW;
    default:
-      assert( 0 );
+      assert(0);
    }
    return 0;
 }
@@ -72,21 +72,19 @@ tgsi_util_get_src_register_swizzle(
 
 unsigned
 tgsi_util_get_full_src_register_swizzle(
-   const struct tgsi_full_src_register  *reg,
-   unsigned component )
+   const struct tgsi_full_src_register *reg,
+   unsigned component)
 {
-   return tgsi_util_get_src_register_swizzle(
-      &reg->SrcRegister,
-      component );
+   return tgsi_util_get_src_register_swizzle(&reg->Register, component);
 }
 
+
 void
-tgsi_util_set_src_register_swizzle(
-   struct tgsi_src_register *reg,
-   unsigned swizzle,
-   unsigned component )
+tgsi_util_set_src_register_swizzle(struct tgsi_src_register *reg,
+                                   unsigned swizzle,
+                                   unsigned component)
 {
-   switch( component ) {
+   switch (component) {
    case 0:
       reg->SwizzleX = swizzle;
       break;
@@ -100,21 +98,22 @@ tgsi_util_set_src_register_swizzle(
       reg->SwizzleW = swizzle;
       break;
    default:
-      assert( 0 );
+      assert(0);
    }
 }
 
+
 unsigned
 tgsi_util_get_full_src_register_sign_mode(
-   const struct  tgsi_full_src_register *reg,
-   unsigned component )
+   const struct tgsi_full_src_register *reg,
+   UNUSED unsigned component)
 {
    unsigned sign_mode;
 
-   if( reg->SrcRegisterExtMod.Absolute ) {
+   if (reg->Register.Absolute) {
       /* Consider only the post-abs negation. */
 
-      if( reg->SrcRegisterExtMod.Negate ) {
+      if (reg->Register.Negate) {
          sign_mode = TGSI_UTIL_SIGN_SET;
       }
       else {
@@ -122,17 +121,7 @@ tgsi_util_get_full_src_register_sign_mode(
       }
    }
    else {
-      /* Accumulate the three negations. */
-
-      unsigned negate;
-
-      negate = reg->SrcRegister.Negate;
-
-      if( reg->SrcRegisterExtMod.Negate ) {
-         negate = !negate;
-      }
-
-      if( negate ) {
+      if (reg->Register.Negate) {
          sign_mode = TGSI_UTIL_SIGN_TOGGLE;
       }
       else {
@@ -143,38 +132,423 @@ tgsi_util_get_full_src_register_sign_mode(
    return sign_mode;
 }
 
+
 void
-tgsi_util_set_full_src_register_sign_mode(
-   struct tgsi_full_src_register *reg,
-   unsigned sign_mode )
+tgsi_util_set_full_src_register_sign_mode(struct tgsi_full_src_register *reg,
+                                          unsigned sign_mode)
 {
-   switch (sign_mode)
-   {
+   switch (sign_mode) {
    case TGSI_UTIL_SIGN_CLEAR:
-      reg->SrcRegister.Negate = 0;
-      reg->SrcRegisterExtMod.Absolute = 1;
-      reg->SrcRegisterExtMod.Negate = 0;
+      reg->Register.Negate = 0;
+      reg->Register.Absolute = 1;
       break;
 
    case TGSI_UTIL_SIGN_SET:
-      reg->SrcRegister.Negate = 0;
-      reg->SrcRegisterExtMod.Absolute = 1;
-      reg->SrcRegisterExtMod.Negate = 1;
+      reg->Register.Absolute = 1;
+      reg->Register.Negate = 1;
       break;
 
    case TGSI_UTIL_SIGN_TOGGLE:
-      reg->SrcRegister.Negate = 1;
-      reg->SrcRegisterExtMod.Absolute = 0;
-      reg->SrcRegisterExtMod.Negate = 0;
+      reg->Register.Negate = 1;
+      reg->Register.Absolute = 0;
       break;
 
    case TGSI_UTIL_SIGN_KEEP:
-      reg->SrcRegister.Negate = 0;
-      reg->SrcRegisterExtMod.Absolute = 0;
-      reg->SrcRegisterExtMod.Negate = 0;
+      reg->Register.Negate = 0;
+      reg->Register.Absolute = 0;
+      break;
+
+   default:
+      assert(0);
+   }
+}
+
+
+/**
+ * Determine which channels of the specificed src register are effectively
+ * used by this instruction.
+ */
+unsigned
+tgsi_util_get_inst_usage_mask(const struct tgsi_full_instruction *inst,
+                              unsigned src_idx)
+{
+   const struct tgsi_full_src_register *src = &inst->Src[src_idx];
+   unsigned write_mask = inst->Dst[0].Register.WriteMask;
+   unsigned read_mask;
+   unsigned usage_mask;
+   unsigned chan;
+
+   switch (inst->Instruction.Opcode) {
+   case TGSI_OPCODE_IF:
+   case TGSI_OPCODE_UIF:
+   case TGSI_OPCODE_EMIT:
+   case TGSI_OPCODE_ENDPRIM:
+   case TGSI_OPCODE_RCP:
+   case TGSI_OPCODE_RSQ:
+   case TGSI_OPCODE_SQRT:
+   case TGSI_OPCODE_EX2:
+   case TGSI_OPCODE_LG2:
+   case TGSI_OPCODE_SIN:
+   case TGSI_OPCODE_COS:
+   case TGSI_OPCODE_POW: /* reads src0.x and src1.x */
+   case TGSI_OPCODE_UP2H:
+   case TGSI_OPCODE_UP2US:
+   case TGSI_OPCODE_UP4B:
+   case TGSI_OPCODE_UP4UB:
+   case TGSI_OPCODE_MEMBAR:
+   case TGSI_OPCODE_BALLOT:
+      read_mask = TGSI_WRITEMASK_X;
+      break;
+
+   case TGSI_OPCODE_DP2:
+   case TGSI_OPCODE_PK2H:
+   case TGSI_OPCODE_PK2US:
+   case TGSI_OPCODE_DFRACEXP:
+   case TGSI_OPCODE_F2D:
+   case TGSI_OPCODE_I2D:
+   case TGSI_OPCODE_U2D:
+   case TGSI_OPCODE_F2U64:
+   case TGSI_OPCODE_F2I64:
+   case TGSI_OPCODE_U2I64:
+   case TGSI_OPCODE_I2I64:
+   case TGSI_OPCODE_TXQS: /* bindless handle possible */
+   case TGSI_OPCODE_RESQ: /* bindless handle possible */
+      read_mask = TGSI_WRITEMASK_XY;
+      break;
+
+   case TGSI_OPCODE_TXQ:
+      if (src_idx == 0)
+         read_mask = TGSI_WRITEMASK_X;
+      else
+         read_mask = TGSI_WRITEMASK_XY;  /* bindless handle possible */
+      break;
+
+   case TGSI_OPCODE_DP3:
+      read_mask = TGSI_WRITEMASK_XYZ;
+      break;
+
+   case TGSI_OPCODE_DSEQ:
+   case TGSI_OPCODE_DSNE:
+   case TGSI_OPCODE_DSLT:
+   case TGSI_OPCODE_DSGE:
+   case TGSI_OPCODE_DP4:
+   case TGSI_OPCODE_PK4B:
+   case TGSI_OPCODE_PK4UB:
+   case TGSI_OPCODE_D2F:
+   case TGSI_OPCODE_D2I:
+   case TGSI_OPCODE_D2U:
+   case TGSI_OPCODE_I2F:
+   case TGSI_OPCODE_U2F:
+   case TGSI_OPCODE_U64SEQ:
+   case TGSI_OPCODE_U64SNE:
+   case TGSI_OPCODE_U64SLT:
+   case TGSI_OPCODE_U64SGE:
+   case TGSI_OPCODE_U642F:
+   case TGSI_OPCODE_I64SLT:
+   case TGSI_OPCODE_I64SGE:
+   case TGSI_OPCODE_I642F:
+      read_mask = TGSI_WRITEMASK_XYZW;
+      break;
+
+   case TGSI_OPCODE_LIT:
+      read_mask = write_mask & TGSI_WRITEMASK_YZ ?
+                     TGSI_WRITEMASK_XY | TGSI_WRITEMASK_W : 0;
+      break;
+
+   case TGSI_OPCODE_EXP:
+   case TGSI_OPCODE_LOG:
+      read_mask = write_mask & TGSI_WRITEMASK_XYZ ? TGSI_WRITEMASK_X : 0;
+      break;
+
+   case TGSI_OPCODE_DST:
+      if (src_idx == 0)
+         read_mask = TGSI_WRITEMASK_YZ;
+      else
+         read_mask = TGSI_WRITEMASK_YW;
+      break;
+
+   case TGSI_OPCODE_DLDEXP:
+      if (src_idx == 0) {
+         read_mask = write_mask;
+      } else {
+         read_mask =
+            (write_mask & TGSI_WRITEMASK_XY ? TGSI_WRITEMASK_X : 0) |
+            (write_mask & TGSI_WRITEMASK_ZW ? TGSI_WRITEMASK_Z : 0);
+      }
+      break;
+
+   case TGSI_OPCODE_READ_INVOC:
+      if (src_idx == 0)
+         read_mask = write_mask;
+      else
+         read_mask = TGSI_WRITEMASK_X;
+      break;
+
+   case TGSI_OPCODE_FBFETCH:
+      read_mask = 0; /* not a real register read */
+      break;
+
+   case TGSI_OPCODE_TEX:
+   case TGSI_OPCODE_TEX_LZ:
+   case TGSI_OPCODE_TXF_LZ:
+   case TGSI_OPCODE_TXF:
+   case TGSI_OPCODE_TXB:
+   case TGSI_OPCODE_TXL:
+   case TGSI_OPCODE_TXP:
+   case TGSI_OPCODE_TXD:
+   case TGSI_OPCODE_TEX2:
+   case TGSI_OPCODE_TXB2:
+   case TGSI_OPCODE_TXL2:
+   case TGSI_OPCODE_LODQ:
+   case TGSI_OPCODE_TG4: {
+      unsigned dim_layer =
+         tgsi_util_get_texture_coord_dim(inst->Texture.Texture);
+      unsigned dim_layer_shadow, dim;
+
+      /* Add shadow. */
+      if (tgsi_is_shadow_target(inst->Texture.Texture)) {
+         dim_layer_shadow = dim_layer + 1;
+         if (inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D)
+            dim_layer_shadow = 3;
+      } else {
+         dim_layer_shadow = dim_layer;
+      }
+
+      /* Remove layer. */
+      if (tgsi_is_array_sampler(inst->Texture.Texture))
+         dim = dim_layer - 1;
+      else
+         dim = dim_layer;
+
+      read_mask = TGSI_WRITEMASK_XY; /* bindless handle in the last operand */
+
+      switch (src_idx) {
+      case 0:
+         if (inst->Instruction.Opcode == TGSI_OPCODE_LODQ)
+            read_mask = u_bit_consecutive(0, dim);
+         else
+            read_mask = u_bit_consecutive(0, dim_layer_shadow) & 0xf;
+
+         if (inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D)
+            read_mask &= ~TGSI_WRITEMASK_Y;
+
+         if (inst->Instruction.Opcode == TGSI_OPCODE_TXF ||
+             inst->Instruction.Opcode == TGSI_OPCODE_TXB ||
+             inst->Instruction.Opcode == TGSI_OPCODE_TXL ||
+             inst->Instruction.Opcode == TGSI_OPCODE_TXP)
+            read_mask |= TGSI_WRITEMASK_W;
+         break;
+
+      case 1:
+         if (inst->Instruction.Opcode == TGSI_OPCODE_TXD)
+            read_mask = u_bit_consecutive(0, dim);
+         else if (inst->Instruction.Opcode == TGSI_OPCODE_TEX2 ||
+                  inst->Instruction.Opcode == TGSI_OPCODE_TXB2 ||
+                  inst->Instruction.Opcode == TGSI_OPCODE_TXL2 ||
+                  inst->Instruction.Opcode == TGSI_OPCODE_TG4)
+            read_mask = TGSI_WRITEMASK_X;
+         break;
+
+      case 2:
+         if (inst->Instruction.Opcode == TGSI_OPCODE_TXD)
+            read_mask = u_bit_consecutive(0, dim);
+         break;
+      }
+      break;
+   }
+
+   case TGSI_OPCODE_LOAD:
+      if (src_idx == 0) {
+         read_mask = TGSI_WRITEMASK_XY; /* bindless handle possible */
+      } else {
+         unsigned dim = tgsi_util_get_texture_coord_dim(inst->Memory.Texture);
+         read_mask = u_bit_consecutive(0, dim);
+      }
       break;
 
+   case TGSI_OPCODE_STORE:
+      if (src_idx == 0) {
+         unsigned dim = tgsi_util_get_texture_coord_dim(inst->Memory.Texture);
+         read_mask = u_bit_consecutive(0, dim);
+      } else {
+         read_mask = TGSI_WRITEMASK_XYZW;
+      }
+      break;
+
+   case TGSI_OPCODE_ATOMUADD:
+   case TGSI_OPCODE_ATOMXCHG:
+   case TGSI_OPCODE_ATOMCAS:
+   case TGSI_OPCODE_ATOMAND:
+   case TGSI_OPCODE_ATOMOR:
+   case TGSI_OPCODE_ATOMXOR:
+   case TGSI_OPCODE_ATOMUMIN:
+   case TGSI_OPCODE_ATOMUMAX:
+   case TGSI_OPCODE_ATOMIMIN:
+   case TGSI_OPCODE_ATOMIMAX:
+      if (src_idx == 0) {
+         read_mask = TGSI_WRITEMASK_XY; /* bindless handle possible */
+      } else if (src_idx == 1) {
+         unsigned dim = tgsi_util_get_texture_coord_dim(inst->Memory.Texture);
+         read_mask = u_bit_consecutive(0, dim);
+      } else {
+         read_mask = TGSI_WRITEMASK_XYZW;
+      }
+      break;
+
+   case TGSI_OPCODE_INTERP_CENTROID:
+   case TGSI_OPCODE_INTERP_SAMPLE:
+   case TGSI_OPCODE_INTERP_OFFSET:
+      if (src_idx == 0)
+         read_mask = write_mask;
+      else if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_OFFSET)
+         read_mask = TGSI_WRITEMASK_XY; /* offset */
+      else
+         read_mask = TGSI_WRITEMASK_X; /* sample */
+      break;
+
+   default:
+      if (tgsi_get_opcode_info(inst->Instruction.Opcode)->output_mode ==
+          TGSI_OUTPUT_COMPONENTWISE)
+         read_mask = write_mask;
+      else
+         read_mask = TGSI_WRITEMASK_XYZW; /* assume all channels are read */
+      break;
+   }
+
+   usage_mask = 0;
+   for (chan = 0; chan < 4; ++chan) {
+      if (read_mask & (1 << chan)) {
+         usage_mask |= 1 << tgsi_util_get_full_src_register_swizzle(src, chan);
+      }
+   }
+
+   return usage_mask;
+}
+
+/**
+ * Convert a tgsi_ind_register into a tgsi_src_register
+ */
+struct tgsi_src_register
+tgsi_util_get_src_from_ind(const struct tgsi_ind_register *reg)
+{
+   struct tgsi_src_register src = { 0 };
+
+   src.File = reg->File;
+   src.Index = reg->Index;
+   src.SwizzleX = reg->Swizzle;
+   src.SwizzleY = reg->Swizzle;
+   src.SwizzleZ = reg->Swizzle;
+   src.SwizzleW = reg->Swizzle;
+
+   return src;
+}
+
+/**
+ * Return the dimension of the texture coordinates (layer included for array
+ * textures), as well as the location of the shadow reference value or the
+ * sample index.
+ */
+int
+tgsi_util_get_texture_coord_dim(enum tgsi_texture_type tgsi_tex)
+{
+   /*
+    * Depending on the texture target, (src0.xyzw, src1.x) is interpreted
+    * differently:
+    *
+    *   (s, X, X, X, X),               for BUFFER
+    *   (s, X, X, X, X),               for 1D
+    *   (s, t, X, X, X),               for 2D, RECT
+    *   (s, t, r, X, X),               for 3D, CUBE
+    *
+    *   (s, layer, X, X, X),           for 1D_ARRAY
+    *   (s, t, layer, X, X),           for 2D_ARRAY
+    *   (s, t, r, layer, X),           for CUBE_ARRAY
+    *
+    *   (s, X, shadow, X, X),          for SHADOW1D
+    *   (s, t, shadow, X, X),          for SHADOW2D, SHADOWRECT
+    *   (s, t, r, shadow, X),          for SHADOWCUBE
+    *
+    *   (s, layer, shadow, X, X),      for SHADOW1D_ARRAY
+    *   (s, t, layer, shadow, X),      for SHADOW2D_ARRAY
+    *   (s, t, r, layer, shadow),      for SHADOWCUBE_ARRAY
+    *
+    *   (s, t, sample, X, X),          for 2D_MSAA
+    *   (s, t, layer, sample, X),      for 2D_ARRAY_MSAA
+    */
+   switch (tgsi_tex) {
+   case TGSI_TEXTURE_BUFFER:
+   case TGSI_TEXTURE_1D:
+   case TGSI_TEXTURE_SHADOW1D:
+      return 1;
+   case TGSI_TEXTURE_2D:
+   case TGSI_TEXTURE_RECT:
+   case TGSI_TEXTURE_1D_ARRAY:
+   case TGSI_TEXTURE_SHADOW2D:
+   case TGSI_TEXTURE_SHADOWRECT:
+   case TGSI_TEXTURE_SHADOW1D_ARRAY:
+   case TGSI_TEXTURE_2D_MSAA:
+      return 2;
+   case TGSI_TEXTURE_3D:
+   case TGSI_TEXTURE_CUBE:
+   case TGSI_TEXTURE_2D_ARRAY:
+   case TGSI_TEXTURE_SHADOWCUBE:
+   case TGSI_TEXTURE_SHADOW2D_ARRAY:
+   case TGSI_TEXTURE_2D_ARRAY_MSAA:
+      return 3;
+   case TGSI_TEXTURE_CUBE_ARRAY:
+   case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+      return 4;
+   default:
+      assert(!"unknown texture target");
+      return 0;
+   }
+}
+
+
+/**
+ * Given a TGSI_TEXTURE_x target, return register component where the
+ * shadow reference/distance coordinate is found.  Typically, components
+ * 0 and 1 are the (s,t) texcoords and component 2 or 3 hold the shadow
+ * reference value.  But if we return 4, it means the reference value is
+ * found in the 0th component of the second coordinate argument to the
+ * TEX2 instruction.
+ */
+int
+tgsi_util_get_shadow_ref_src_index(enum tgsi_texture_type tgsi_tex)
+{
+   switch (tgsi_tex) {
+   case TGSI_TEXTURE_SHADOW1D:
+   case TGSI_TEXTURE_SHADOW2D:
+   case TGSI_TEXTURE_SHADOWRECT:
+   case TGSI_TEXTURE_SHADOW1D_ARRAY:
+      return 2;
+   case TGSI_TEXTURE_SHADOWCUBE:
+   case TGSI_TEXTURE_SHADOW2D_ARRAY:
+   case TGSI_TEXTURE_2D_MSAA:
+   case TGSI_TEXTURE_2D_ARRAY_MSAA:
+      return 3;
+   case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+      return 4;
+   default:
+      /* no shadow nor sample */
+      return -1;
+   }
+}
+
+
+boolean
+tgsi_is_shadow_target(enum tgsi_texture_type target)
+{
+   switch (target) {
+   case TGSI_TEXTURE_SHADOW1D:
+   case TGSI_TEXTURE_SHADOW2D:
+   case TGSI_TEXTURE_SHADOWRECT:
+   case TGSI_TEXTURE_SHADOW1D_ARRAY:
+   case TGSI_TEXTURE_SHADOW2D_ARRAY:
+   case TGSI_TEXTURE_SHADOWCUBE:
+   case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+      return TRUE;
    default:
-      assert( 0 );
+      return FALSE;
    }
 }