ilo: add ilo_state_sampler
authorChia-I Wu <olvaffe@gmail.com>
Wed, 13 May 2015 05:10:54 +0000 (13:10 +0800)
committerChia-I Wu <olvaffe@gmail.com>
Sun, 14 Jun 2015 15:00:04 +0000 (23:00 +0800)
We want to replace ilo_sampler_cso with ilo_state_sampler.

src/gallium/drivers/ilo/Makefile.sources
src/gallium/drivers/ilo/core/ilo_state_sampler.c [new file with mode: 0644]
src/gallium/drivers/ilo/core/ilo_state_sampler.h [new file with mode: 0644]

index 587850e..3bb3dde 100644 (file)
@@ -23,6 +23,8 @@ C_SOURCES := \
        core/ilo_state_3d.h \
        core/ilo_state_3d_bottom.c \
        core/ilo_state_3d_top.c \
+       core/ilo_state_sampler.c \
+       core/ilo_state_sampler.h \
        core/ilo_state_surface.c \
        core/ilo_state_surface.h \
        core/ilo_state_zs.c \
diff --git a/src/gallium/drivers/ilo/core/ilo_state_sampler.c b/src/gallium/drivers/ilo/core/ilo_state_sampler.c
new file mode 100644 (file)
index 0000000..3787f68
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2012-2015 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "util/u_half.h"
+
+#include "ilo_debug.h"
+#include "ilo_state_surface.h"
+#include "ilo_state_sampler.h"
+
+static bool
+sampler_validate_gen6_non_normalized(const struct ilo_dev *dev,
+                                     const struct ilo_state_sampler_info *info)
+{
+   const enum gen_texcoord_mode addr_ctrls[3] = {
+      info->tcx_ctrl, info->tcy_ctrl, info->tcz_ctrl,
+   };
+   int i;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   /*
+    * From the Ivy Bridge PRM, volume 4 part 1, page 98:
+    *
+    *     "The following state must be set as indicated if this field
+    *      (Non-normalized Coordinate Enable) is enabled:
+    *
+    *      - TCX/Y/Z Address Control Mode must be TEXCOORDMODE_CLAMP,
+    *        TEXCOORDMODE_HALF_BORDER, or TEXCOORDMODE_CLAMP_BORDER.
+    *      - Surface Type must be SURFTYPE_2D or SURFTYPE_3D.
+    *      - Mag Mode Filter must be MAPFILTER_NEAREST or
+    *        MAPFILTER_LINEAR.
+    *      - Min Mode Filter must be MAPFILTER_NEAREST or
+    *        MAPFILTER_LINEAR.
+    *      - Mip Mode Filter must be MIPFILTER_NONE.
+    *      - Min LOD must be 0.
+    *      - Max LOD must be 0.
+    *      - MIP Count must be 0.
+    *      - Surface Min LOD must be 0.
+    *      - Texture LOD Bias must be 0."
+    */
+   for (i = 0; i < 3; i++) {
+      switch (addr_ctrls[i]) {
+      case GEN6_TEXCOORDMODE_CLAMP:
+      case GEN6_TEXCOORDMODE_CLAMP_BORDER:
+      case GEN8_TEXCOORDMODE_HALF_BORDER:
+         break;
+      default:
+         assert(!"bad non-normalized coordinate wrap mode");
+         break;
+      }
+   }
+
+   assert(info->mip_filter == GEN6_MIPFILTER_NONE);
+
+   assert((info->min_filter == GEN6_MAPFILTER_NEAREST ||
+           info->min_filter == GEN6_MAPFILTER_LINEAR) &&
+          (info->mag_filter == GEN6_MAPFILTER_NEAREST ||
+           info->mag_filter == GEN6_MAPFILTER_LINEAR));
+
+   assert(info->min_lod == 0.0f &&
+          info->max_lod == 0.0f &&
+          info->lod_bias == 0.0f);
+
+   return true;
+}
+
+static bool
+sampler_validate_gen6_sampler(const struct ilo_dev *dev,
+                              const struct ilo_state_sampler_info *info)
+{
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   if (info->non_normalized &&
+       !sampler_validate_gen6_non_normalized(dev, info))
+      return false;
+
+   if (ilo_dev_gen(dev) < ILO_GEN(8)) {
+       assert(info->tcx_ctrl != GEN8_TEXCOORDMODE_HALF_BORDER &&
+              info->tcy_ctrl != GEN8_TEXCOORDMODE_HALF_BORDER &&
+              info->tcz_ctrl != GEN8_TEXCOORDMODE_HALF_BORDER);
+   }
+
+   return true;
+}
+
+static uint32_t
+sampler_get_gen6_integer_filters(const struct ilo_dev *dev,
+                                 const struct ilo_state_sampler_info *info)
+{
+   /*
+    * From the Sandy Bridge PRM, volume 4 part 1, page 103:
+    *
+    *     "MIPFILTER_LINEAR is not supported for surface formats that do not
+    *      support "Sampling Engine Filtering" as indicated in the Surface
+    *      Formats table unless using the sample_c message type."
+    *
+    *     "Only MAPFILTER_NEAREST is supported for surface formats that do not
+    *      support "Sampling Engine Filtering" as indicated in the Surface
+    *      Formats table unless using the sample_c message type.
+    */
+   const enum gen_mip_filter mip_filter =
+      (info->mip_filter == GEN6_MIPFILTER_LINEAR) ?
+      GEN6_MIPFILTER_NEAREST : info->mip_filter;
+   const enum gen_map_filter min_filter = GEN6_MAPFILTER_NEAREST;
+   const enum gen_map_filter mag_filter = GEN6_MAPFILTER_NEAREST;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   return mip_filter << GEN6_SAMPLER_DW0_MIP_FILTER__SHIFT |
+          mag_filter << GEN6_SAMPLER_DW0_MAG_FILTER__SHIFT |
+          min_filter << GEN6_SAMPLER_DW0_MIN_FILTER__SHIFT;
+}
+
+static uint32_t
+sampler_get_gen6_3d_filters(const struct ilo_dev *dev,
+                            const struct ilo_state_sampler_info *info)
+{
+   const enum gen_mip_filter mip_filter = info->mip_filter;
+   /*
+    * From the Sandy Bridge PRM, volume 4 part 1, page 103:
+    *
+    *     "Only MAPFILTER_NEAREST and MAPFILTER_LINEAR are supported for
+    *      surfaces of type SURFTYPE_3D."
+    */
+   const enum gen_map_filter min_filter =
+      (info->min_filter == GEN6_MAPFILTER_NEAREST ||
+       info->min_filter == GEN6_MAPFILTER_LINEAR) ?
+      info->min_filter : GEN6_MAPFILTER_LINEAR;
+   const enum gen_map_filter mag_filter =
+      (info->mag_filter == GEN6_MAPFILTER_NEAREST ||
+       info->mag_filter == GEN6_MAPFILTER_LINEAR) ?
+       info->mag_filter : GEN6_MAPFILTER_LINEAR;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   return mip_filter << GEN6_SAMPLER_DW0_MIP_FILTER__SHIFT |
+          mag_filter << GEN6_SAMPLER_DW0_MAG_FILTER__SHIFT |
+          min_filter << GEN6_SAMPLER_DW0_MIN_FILTER__SHIFT;
+}
+
+static uint32_t
+get_gen6_addr_controls(const struct ilo_dev *dev,
+                       enum gen_texcoord_mode tcx_ctrl,
+                       enum gen_texcoord_mode tcy_ctrl,
+                       enum gen_texcoord_mode tcz_ctrl)
+{
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
+      return tcx_ctrl << GEN7_SAMPLER_DW3_U_WRAP__SHIFT |
+             tcy_ctrl << GEN7_SAMPLER_DW3_V_WRAP__SHIFT |
+             tcz_ctrl << GEN7_SAMPLER_DW3_R_WRAP__SHIFT;
+   } else {
+      return tcx_ctrl << GEN6_SAMPLER_DW1_U_WRAP__SHIFT |
+             tcy_ctrl << GEN6_SAMPLER_DW1_V_WRAP__SHIFT |
+             tcz_ctrl << GEN6_SAMPLER_DW1_R_WRAP__SHIFT;
+   }
+}
+
+static uint32_t
+sampler_get_gen6_1d_addr_controls(const struct ilo_dev *dev,
+                                  const struct ilo_state_sampler_info *info)
+{
+   const enum gen_texcoord_mode tcx_ctrl =
+      (info->tcx_ctrl == GEN6_TEXCOORDMODE_CUBE) ?
+      GEN6_TEXCOORDMODE_CLAMP : info->tcx_ctrl;
+   /*
+    * From the Ivy Bridge PRM, volume 4 part 1, page 100:
+    *
+    *     "If this field (TCY Address Control Mode) is set to
+    *      TEXCOORDMODE_CLAMP_BORDER or TEXCOORDMODE_HALF_BORDER and a 1D
+    *      surface is sampled, incorrect blending with the border color in the
+    *      vertical direction may occur."
+    */
+   const enum gen_texcoord_mode tcy_ctrl = GEN6_TEXCOORDMODE_CLAMP;
+   const enum gen_texcoord_mode tcz_ctrl = GEN6_TEXCOORDMODE_CLAMP;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   return get_gen6_addr_controls(dev, tcx_ctrl, tcy_ctrl, tcz_ctrl);
+}
+
+static uint32_t
+sampler_get_gen6_2d_3d_addr_controls(const struct ilo_dev *dev,
+                                     const struct ilo_state_sampler_info *info)
+{
+   const enum gen_texcoord_mode tcx_ctrl =
+      (info->tcx_ctrl == GEN6_TEXCOORDMODE_CUBE) ?
+      GEN6_TEXCOORDMODE_CLAMP : info->tcx_ctrl;
+   const enum gen_texcoord_mode tcy_ctrl =
+      (info->tcy_ctrl == GEN6_TEXCOORDMODE_CUBE) ?
+      GEN6_TEXCOORDMODE_CLAMP : info->tcy_ctrl;
+   /*
+    * From the Sandy Bridge PRM, volume 4 part 1, page 108:
+    *
+    *     "[DevSNB]: if this field (TCZ Address Control Mode) is set to
+    *      TEXCOORDMODE_CLAMP_BORDER samples outside the map will clamp to 0
+    *      instead of boarder color"
+    *
+    * From the Ivy Bridge PRM, volume 4 part 1, page 100:
+    *
+    *     "If this field is set to TEXCOORDMODE_CLAMP_BORDER for 3D maps on
+    *      formats without an alpha channel, samples straddling the map in the
+    *      Z direction may have their alpha channels off by 1."
+    *
+    * Do we want to do something here?
+    */
+   const enum gen_texcoord_mode tcz_ctrl =
+      (info->tcz_ctrl == GEN6_TEXCOORDMODE_CUBE) ?
+      GEN6_TEXCOORDMODE_CLAMP : info->tcz_ctrl;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   return get_gen6_addr_controls(dev, tcx_ctrl, tcy_ctrl, tcz_ctrl);
+}
+
+static uint32_t
+sampler_get_gen6_cube_addr_controls(const struct ilo_dev *dev,
+                                    const struct ilo_state_sampler_info *info)
+{
+   /*
+    * From the Ivy Bridge PRM, volume 4 part 1, page 99:
+    *
+    *     "When using cube map texture coordinates, only TEXCOORDMODE_CLAMP
+    *      and TEXCOORDMODE_CUBE settings are valid, and each TC component
+    *      must have the same Address Control mode.
+    *
+    *      When TEXCOORDMODE_CUBE is not used accessing a cube map, the map's
+    *      Cube Face Enable field must be programmed to 111111b (all faces
+    *      enabled)."
+    *
+    * From the Haswell PRM, volume 2d, page 278:
+    *
+    *     "When using cube map texture coordinates, each TC component must
+    *      have the same Address Control Mode.
+    *
+    *      When TEXCOORDMODE_CUBE is not used accessing a cube map, the map's
+    *      Cube Face Enable field must be programmed to 111111b (all faces
+    *      enabled)."
+    *
+    * We always enable all cube faces and only need to make sure all address
+    * control modes are the same.
+    */
+   const enum gen_texcoord_mode tcx_ctrl =
+      (ilo_dev_gen(dev) >= ILO_GEN(7.5) ||
+       info->tcx_ctrl == GEN6_TEXCOORDMODE_CUBE ||
+       info->tcx_ctrl == GEN6_TEXCOORDMODE_CLAMP) ?
+      info->tcx_ctrl : GEN6_TEXCOORDMODE_CLAMP;
+   const enum gen_texcoord_mode tcy_ctrl = tcx_ctrl;
+   const enum gen_texcoord_mode tcz_ctrl = tcx_ctrl;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   return get_gen6_addr_controls(dev, tcx_ctrl, tcy_ctrl, tcz_ctrl);
+}
+
+static uint16_t
+get_gen6_lod_bias(const struct ilo_dev *dev, float bias)
+{
+   /* [-16.0, 16.0) in S4.6 or S4.8 */
+   const int fbits = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 8 : 6;
+   const float max = 16.0f;
+   const float scale = (float) (1 << fbits);
+   const int mask = (1 << (1 + 4 + fbits)) - 1;
+   const int scaled_max = (16 << fbits) - 1;
+   int scaled;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   if (bias > max)
+      bias = max;
+   else if (bias < -max)
+      bias = -max;
+
+   scaled = (int) (bias * scale);
+   if (scaled > scaled_max)
+      scaled = scaled_max;
+
+   return (scaled & mask);
+}
+
+static uint16_t
+get_gen6_lod_clamp(const struct ilo_dev *dev, float clamp)
+{
+   /* [0.0, 13.0] in U4.6 or [0.0, 14.0] in U4.8 */
+   const int fbits = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 8 : 6;
+   const float max = (ilo_dev_gen(dev) >= ILO_GEN(7)) ? 14.0f : 13.0f;
+   const float scale = (float) (1 << fbits);
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   if (clamp > max)
+      clamp = max;
+   else if (clamp < 0.0f)
+      clamp = 0.0f;
+
+   return (int) (clamp * scale);
+}
+
+static bool
+sampler_set_gen6_SAMPLER_STATE(struct ilo_state_sampler *sampler,
+                               const struct ilo_dev *dev,
+                               const struct ilo_state_sampler_info *info)
+{
+   uint16_t lod_bias, max_lod, min_lod;
+   uint32_t dw0, dw1, dw3;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   if (!sampler_validate_gen6_sampler(dev, info))
+      return false;
+
+   /*
+    * From the Ivy Bridge PRM, volume 4 part 1, page 15:
+    *
+    *     "The per-pixel LOD is computed in an implementation-dependent manner
+    *      and approximates the log2 of the texel/pixel ratio at the given
+    *      pixel. The computation is typically based on the differential
+    *      texel-space distances associated with a one-pixel differential
+    *      distance along the screen x- and y-axes. These texel-space
+    *      distances are computed by evaluating neighboring pixel texture
+    *      coordinates, these coordinates being in units of texels on the base
+    *      MIP level (multiplied by the corresponding surface size in
+    *      texels)."
+    *
+    * Judging from the LOD computation pseudocode on page 16-18, the "base MIP
+    * level" should be given by SurfMinLod.  To summarize, for the "sample"
+    * message,
+    *
+    *   1) LOD is set to log2(texel/pixel ratio).  The number of texels is
+    *      measured against level SurfMinLod.
+    *   2) Bias is added to LOD.
+    *   3) if pre-clamp is enabled, LOD is clamped to [MinLod, MaxLod] first
+    *   4) LOD is compared with Base to determine whether magnification or
+    *      minification is needed.
+    *   5) If magnification is needed, or no mipmapping is requested, LOD is
+    *      set to floor(MinLod).
+    *   6) LOD is clamped to [0, MIPCnt], and SurfMinLod is added to LOD.
+    *
+    * As an example, we could set SurfMinLod to GL_TEXTURE_BASE_LEVEL and Base
+    * to 0 to match GL.  But GL expects LOD to be set to 0, instead of
+    * floor(MinLod), in 5).  Since this is only an issue when MinLod is
+    * greater than or equal to one, and, with Base being 0, a non-zero MinLod
+    * implies minification, we only need to deal with the case when mipmapping
+    * is disabled.  We can thus do:
+    *
+    *   if (MipFilter == MIPFILTER_NONE && MinLod) {
+    *     MinLod = 0;
+    *     MagFilter = MinFilter;
+    *   }
+    */
+
+   lod_bias = get_gen6_lod_bias(dev, info->lod_bias);
+   min_lod = get_gen6_lod_clamp(dev, info->min_lod);
+   max_lod = get_gen6_lod_clamp(dev, info->max_lod);
+
+   dw0 = GEN6_SAMPLER_DW0_LOD_PRECLAMP_ENABLE |
+         0 << GEN6_SAMPLER_DW0_BASE_LOD__SHIFT |
+         info->mip_filter << GEN6_SAMPLER_DW0_MIP_FILTER__SHIFT |
+         info->mag_filter << GEN6_SAMPLER_DW0_MAG_FILTER__SHIFT |
+         info->min_filter << GEN6_SAMPLER_DW0_MIN_FILTER__SHIFT;
+
+   if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
+      dw0 |= GEN7_SAMPLER_DW0_BORDER_COLOR_MODE_DX10_OGL |
+             lod_bias << GEN7_SAMPLER_DW0_LOD_BIAS__SHIFT;
+
+      if (info->min_filter == GEN6_MAPFILTER_ANISOTROPIC ||
+          info->mag_filter == GEN6_MAPFILTER_ANISOTROPIC)
+         dw0 |= GEN7_SAMPLER_DW0_ANISO_ALGO_EWA;
+   } else {
+      dw0 |= lod_bias << GEN6_SAMPLER_DW0_LOD_BIAS__SHIFT |
+             info->shadow_func << GEN6_SAMPLER_DW0_SHADOW_FUNC__SHIFT;
+
+      /*
+       * From the Sandy Bridge PRM, volume 4 part 1, page 102:
+       *
+       *     "(Min and Mag State Not Equal) Must be set to 1 if any of the
+       *      following are true:
+       *
+       *      - Mag Mode Filter and Min Mode Filter are not the same
+       *      - Address Rounding Enable: U address mag filter and U address
+       *        min filter are not the same
+       *      - Address Rounding Enable: V address mag filter and V address
+       *        min filter are not the same
+       *      - Address Rounding Enable: R address mag filter and R address
+       *        min filter are not the same"
+       *
+       * We set address rounding for U, V, and R uniformly.  Only need to
+       * check the filters.
+       */
+      if (info->min_filter != info->mag_filter)
+         dw0 |= GEN6_SAMPLER_DW0_MIN_MAG_NOT_EQUAL;
+   }
+
+   dw1 = 0;
+
+   if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
+      /*
+       * From the Ivy Bridge PRM, volume 4 part 1, page 96:
+       *
+       *     "This field (Cube Surface Control Mode) must be set to
+       *      CUBECTRLMODE_PROGRAMMED"
+       */
+      dw1 |= min_lod << GEN7_SAMPLER_DW1_MIN_LOD__SHIFT |
+             max_lod << GEN7_SAMPLER_DW1_MAX_LOD__SHIFT |
+             info->shadow_func << GEN7_SAMPLER_DW1_SHADOW_FUNC__SHIFT |
+             GEN7_SAMPLER_DW1_CUBECTRLMODE_PROGRAMMED;
+   } else {
+      dw1 |= min_lod << GEN6_SAMPLER_DW1_MIN_LOD__SHIFT |
+             max_lod << GEN6_SAMPLER_DW1_MAX_LOD__SHIFT |
+             GEN6_SAMPLER_DW1_CUBECTRLMODE_PROGRAMMED |
+             info->tcx_ctrl << GEN6_SAMPLER_DW1_U_WRAP__SHIFT |
+             info->tcy_ctrl << GEN6_SAMPLER_DW1_V_WRAP__SHIFT |
+             info->tcz_ctrl << GEN6_SAMPLER_DW1_R_WRAP__SHIFT;
+   }
+
+   dw3 = info->max_anisotropy << GEN6_SAMPLER_DW3_MAX_ANISO__SHIFT;
+
+   /* round the coordinates for linear filtering */
+   if (info->min_filter != GEN6_MAPFILTER_NEAREST) {
+      dw3 |= GEN6_SAMPLER_DW3_U_MIN_ROUND |
+             GEN6_SAMPLER_DW3_V_MIN_ROUND |
+             GEN6_SAMPLER_DW3_R_MIN_ROUND;
+   }
+   if (info->mag_filter != GEN6_MAPFILTER_NEAREST) {
+      dw3 |= GEN6_SAMPLER_DW3_U_MAG_ROUND |
+             GEN6_SAMPLER_DW3_V_MAG_ROUND |
+             GEN6_SAMPLER_DW3_R_MAG_ROUND;
+   }
+
+   if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
+      dw3 |= GEN7_SAMPLER_DW3_TRIQUAL_FULL |
+             info->tcx_ctrl << GEN7_SAMPLER_DW3_U_WRAP__SHIFT |
+             info->tcy_ctrl << GEN7_SAMPLER_DW3_V_WRAP__SHIFT |
+             info->tcz_ctrl << GEN7_SAMPLER_DW3_R_WRAP__SHIFT;
+
+      if (info->non_normalized)
+         dw3 |= GEN7_SAMPLER_DW3_NON_NORMALIZED_COORD;
+   } else {
+      if (info->non_normalized)
+         dw3 |= GEN6_SAMPLER_DW3_NON_NORMALIZED_COORD;
+   }
+
+   STATIC_ASSERT(ARRAY_SIZE(sampler->sampler) >= 3);
+   sampler->sampler[0] = dw0;
+   sampler->sampler[1] = dw1;
+   sampler->sampler[2] = dw3;
+
+   sampler->filter_integer = sampler_get_gen6_integer_filters(dev, info);
+   sampler->filter_3d = sampler_get_gen6_3d_filters(dev, info);
+   sampler->addr_ctrl_1d = sampler_get_gen6_1d_addr_controls(dev, info);
+   sampler->addr_ctrl_2d_3d = sampler_get_gen6_2d_3d_addr_controls(dev, info);
+   sampler->addr_ctrl_cube = sampler_get_gen6_cube_addr_controls(dev, info);
+
+   sampler->non_normalized = info->non_normalized;
+
+   /*
+    * From the Sandy Bridge PRM, volume 4 part 1, page 21:
+    *
+    *     "[DevSNB] Errata: Incorrect behavior is observed in cases where the
+    *      min and mag mode filters are different and SurfMinLOD is nonzero.
+    *      The determination of MagMode uses the following equation instead of
+    *      the one in the above pseudocode:
+    *
+    *      MagMode = (LOD + SurfMinLOD - Base <= 0)"
+    *
+    * As a way to work around that, request Base to be set to SurfMinLod.
+    */
+   if (ilo_dev_gen(dev) == ILO_GEN(6) &&
+       info->min_filter != info->mag_filter)
+      sampler->base_to_surf_min_lod = true;
+
+   return true;
+}
+
+static bool
+sampler_border_set_gen6_SAMPLER_BORDER_COLOR_STATE(struct ilo_state_sampler_border *border,
+                                                   const struct ilo_dev *dev,
+                                                   const struct ilo_state_sampler_border_info *info)
+{
+   uint32_t dw[12];
+   float rgba[4];
+
+   /*
+    * From the Ivy Bridge PRM, volume 4 part 1, page 117:
+    *
+    *     "For ([DevSNB]), if border color is used, all formats must be
+    *      provided.  Hardware will choose the appropriate format based on
+    *      Surface Format and Texture Border Color Mode. The values
+    *      represented by each format should be the same (other than being
+    *      subject to range-based clamping and precision) to avoid unexpected
+    *      behavior."
+    *
+    * XXX We do not honor info->is_integer yet.
+    */
+
+   ILO_DEV_ASSERT(dev, 6, 6);
+
+   /* make a copy so that we can clamp for SNORM and UNORM */
+   memcpy(rgba, info->rgba.f, sizeof(rgba));
+
+   /* IEEE_FP */
+   dw[1] = fui(rgba[0]);
+   dw[2] = fui(rgba[1]);
+   dw[3] = fui(rgba[2]);
+   dw[4] = fui(rgba[3]);
+
+   /* FLOAT_16 */
+   dw[5] = util_float_to_half(rgba[0]) |
+           util_float_to_half(rgba[1]) << 16;
+   dw[6] = util_float_to_half(rgba[2]) |
+           util_float_to_half(rgba[3]) << 16;
+
+   /* clamp to [-1.0f, 1.0f] */
+   rgba[0] = CLAMP(rgba[0], -1.0f, 1.0f);
+   rgba[1] = CLAMP(rgba[1], -1.0f, 1.0f);
+   rgba[2] = CLAMP(rgba[2], -1.0f, 1.0f);
+   rgba[3] = CLAMP(rgba[3], -1.0f, 1.0f);
+
+   /* SNORM16 */
+   dw[9] =  (int16_t) util_iround(rgba[0] * 32767.0f) |
+            (int16_t) util_iround(rgba[1] * 32767.0f) << 16;
+   dw[10] = (int16_t) util_iround(rgba[2] * 32767.0f) |
+            (int16_t) util_iround(rgba[3] * 32767.0f) << 16;
+
+   /* SNORM8 */
+   dw[11] = (int8_t) util_iround(rgba[0] * 127.0f) |
+            (int8_t) util_iround(rgba[1] * 127.0f) << 8 |
+            (int8_t) util_iround(rgba[2] * 127.0f) << 16 |
+            (int8_t) util_iround(rgba[3] * 127.0f) << 24;
+
+   /* clamp to [0.0f, 1.0f] */
+   rgba[0] = CLAMP(rgba[0], 0.0f, 1.0f);
+   rgba[1] = CLAMP(rgba[1], 0.0f, 1.0f);
+   rgba[2] = CLAMP(rgba[2], 0.0f, 1.0f);
+   rgba[3] = CLAMP(rgba[3], 0.0f, 1.0f);
+
+   /* UNORM8 */
+   dw[0] = (uint8_t) util_iround(rgba[0] * 255.0f) |
+           (uint8_t) util_iround(rgba[1] * 255.0f) << 8 |
+           (uint8_t) util_iround(rgba[2] * 255.0f) << 16 |
+           (uint8_t) util_iround(rgba[3] * 255.0f) << 24;
+
+   /* UNORM16 */
+   dw[7] = (uint16_t) util_iround(rgba[0] * 65535.0f) |
+           (uint16_t) util_iround(rgba[1] * 65535.0f) << 16;
+   dw[8] = (uint16_t) util_iround(rgba[2] * 65535.0f) |
+           (uint16_t) util_iround(rgba[3] * 65535.0f) << 16;
+
+   STATIC_ASSERT(ARRAY_SIZE(border->color) >= 12);
+   memcpy(border->color, dw, sizeof(dw));
+
+   return true;
+}
+
+static bool
+sampler_border_set_gen7_SAMPLER_BORDER_COLOR_STATE(struct ilo_state_sampler_border *border,
+                                                   const struct ilo_dev *dev,
+                                                   const struct ilo_state_sampler_border_info *info)
+{
+   ILO_DEV_ASSERT(dev, 7, 8);
+
+   /*
+    * From the Ivy Bridge PRM, volume 4 part 1, page 116:
+    *
+    *     "In DX10/OGL mode, the format of the border color is
+    *      R32G32B32A32_FLOAT, regardless of the surface format chosen."
+    *
+    * From the Haswell PRM, volume 2d, page 240:
+    *
+    *     "So, SW will have to program the table in SAMPLER_BORDER_COLOR_STATE
+    *      at offsets DWORD16 to 19, as per the integer surface format type."
+    *
+    * From the Broadwell PRM, volume 2d, page 297:
+    *
+    *     "DX10/OGL mode: the format of the border color depends on the format
+    *      of the surface being sampled. If the map format is UINT, then the
+    *      border color format is R32G32B32A32_UINT. If the map format is
+    *      SINT, then the border color format is R32G32B32A32_SINT. Otherwise,
+    *      the border color format is R32G32B32A32_FLOAT."
+    *
+    * XXX every Gen is different
+    */
+
+   STATIC_ASSERT(ARRAY_SIZE(border->color) >= 4);
+   memcpy(border->color, info->rgba.f, sizeof(info->rgba.f));
+
+   return true;
+}
+
+bool
+ilo_state_sampler_init(struct ilo_state_sampler *sampler,
+                       const struct ilo_dev *dev,
+                       const struct ilo_state_sampler_info *info)
+{
+   bool ret = true;
+
+   assert(ilo_is_zeroed(sampler, sizeof(*sampler)));
+
+   ret &= sampler_set_gen6_SAMPLER_STATE(sampler, dev, info);
+
+   assert(ret);
+
+   return ret;
+}
+
+bool
+ilo_state_sampler_init_disabled(struct ilo_state_sampler *sampler,
+                                const struct ilo_dev *dev)
+{
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   assert(ilo_is_zeroed(sampler, sizeof(*sampler)));
+
+   sampler->sampler[0] = GEN6_SAMPLER_DW0_DISABLE;
+   sampler->sampler[1] = 0;
+   sampler->sampler[2] = 0;
+
+   return true;
+}
+
+/**
+ * Modify \p sampler to work with \p surf.  There will be loss of information.
+ * Callers should make a copy of the orignal sampler first.
+ */
+bool
+ilo_state_sampler_set_surface(struct ilo_state_sampler *sampler,
+                              const struct ilo_dev *dev,
+                              const struct ilo_state_surface *surf)
+{
+   uint32_t addr_ctrl;
+
+   ILO_DEV_ASSERT(dev, 6, 8);
+
+   if (sampler->non_normalized) {
+      /* see sampler_validate_gen6_non_normalized() */
+      assert(surf->type == GEN6_SURFTYPE_2D ||
+             surf->type == GEN6_SURFTYPE_3D);
+      assert(!surf->min_lod && !surf->mip_count);
+   }
+
+   if (sampler->base_to_surf_min_lod) {
+      const uint8_t base = surf->min_lod << GEN6_SAMPLER_DW0_BASE_LOD__RADIX;
+
+      sampler->sampler[0] =
+         (sampler->sampler[0] & ~GEN6_SAMPLER_DW0_BASE_LOD__MASK) |
+         base << GEN6_SAMPLER_DW0_BASE_LOD__SHIFT;
+   }
+
+   if (surf->is_integer || surf->type == GEN6_SURFTYPE_3D) {
+      const uint32_t mask = (GEN6_SAMPLER_DW0_MIP_FILTER__MASK |
+                             GEN6_SAMPLER_DW0_MIN_FILTER__MASK |
+                             GEN6_SAMPLER_DW0_MAG_FILTER__MASK);
+      const uint32_t filter = (surf->is_integer) ?
+         sampler->filter_integer : sampler->filter_3d;
+
+      assert((filter & mask) == filter);
+      sampler->sampler[0] = (sampler->sampler[0] & ~mask) |
+                            filter;
+   }
+
+   switch (surf->type) {
+   case GEN6_SURFTYPE_1D:
+      addr_ctrl = sampler->addr_ctrl_1d;
+      break;
+   case GEN6_SURFTYPE_2D:
+   case GEN6_SURFTYPE_3D:
+      addr_ctrl = sampler->addr_ctrl_2d_3d;
+      break;
+   case GEN6_SURFTYPE_CUBE:
+      addr_ctrl = sampler->addr_ctrl_cube;
+      break;
+   default:
+      assert(!"unexpected surface type");
+      addr_ctrl = 0;
+      break;
+   }
+
+   if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
+      const uint32_t mask = (GEN7_SAMPLER_DW3_U_WRAP__MASK |
+                             GEN7_SAMPLER_DW3_V_WRAP__MASK |
+                             GEN7_SAMPLER_DW3_R_WRAP__MASK);
+
+      assert((addr_ctrl & mask) == addr_ctrl);
+      sampler->sampler[2] = (sampler->sampler[2] & ~mask) |
+                            addr_ctrl;
+   } else {
+      const uint32_t mask = (GEN6_SAMPLER_DW1_U_WRAP__MASK |
+                             GEN6_SAMPLER_DW1_V_WRAP__MASK |
+                             GEN6_SAMPLER_DW1_R_WRAP__MASK);
+
+      assert((addr_ctrl & mask) == addr_ctrl);
+      sampler->sampler[1] = (sampler->sampler[1] & ~mask) |
+                            addr_ctrl;
+   }
+
+   return true;
+}
+
+bool
+ilo_state_sampler_border_init(struct ilo_state_sampler_border *border,
+                              const struct ilo_dev *dev,
+                              const struct ilo_state_sampler_border_info *info)
+{
+   bool ret = true;
+
+   if (ilo_dev_gen(dev) >= ILO_GEN(7)) {
+      ret &= sampler_border_set_gen7_SAMPLER_BORDER_COLOR_STATE(border,
+            dev, info);
+   } else {
+      ret &= sampler_border_set_gen6_SAMPLER_BORDER_COLOR_STATE(border,
+            dev, info);
+   }
+
+   assert(ret);
+
+   return ret;
+}
diff --git a/src/gallium/drivers/ilo/core/ilo_state_sampler.h b/src/gallium/drivers/ilo/core/ilo_state_sampler.h
new file mode 100644 (file)
index 0000000..75c7620
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2015 LunarG, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef ILO_STATE_SAMPLER_H
+#define ILO_STATE_SAMPLER_H
+
+#include "genhw/genhw.h"
+
+#include "ilo_core.h"
+#include "ilo_dev.h"
+
+struct ilo_state_surface;
+
+struct ilo_state_sampler_info {
+   bool non_normalized;
+
+   float lod_bias;
+   float min_lod;
+   float max_lod;
+
+   enum gen_mip_filter mip_filter;
+   enum gen_map_filter min_filter;
+   enum gen_map_filter mag_filter;
+   enum gen_aniso_ratio max_anisotropy;
+
+   enum gen_texcoord_mode tcx_ctrl;
+   enum gen_texcoord_mode tcy_ctrl;
+   enum gen_texcoord_mode tcz_ctrl;
+
+   enum gen_prefilter_op shadow_func;
+};
+
+struct ilo_state_sampler_border_info {
+   union {
+      float f[4];
+      uint32_t ui[4];
+   } rgba;
+
+   bool is_integer;
+};
+
+struct ilo_state_sampler {
+   uint32_t sampler[3];
+
+   uint32_t filter_integer;
+   uint32_t filter_3d;
+
+   uint32_t addr_ctrl_1d;
+   uint32_t addr_ctrl_2d_3d;
+   uint32_t addr_ctrl_cube;
+
+   bool non_normalized;
+   bool base_to_surf_min_lod;
+};
+
+struct ilo_state_sampler_border {
+   uint32_t color[12];
+};
+
+bool
+ilo_state_sampler_init(struct ilo_state_sampler *sampler,
+                       const struct ilo_dev *dev,
+                       const struct ilo_state_sampler_info *info);
+
+bool
+ilo_state_sampler_init_disabled(struct ilo_state_sampler *sampler,
+                                const struct ilo_dev *dev);
+
+bool
+ilo_state_sampler_set_surface(struct ilo_state_sampler *sampler,
+                              const struct ilo_dev *dev,
+                              const struct ilo_state_surface *surf);
+
+bool
+ilo_state_sampler_border_init(struct ilo_state_sampler_border *border,
+                              const struct ilo_dev *dev,
+                              const struct ilo_state_sampler_border_info *info);
+
+#endif /* ILO_STATE_SAMPLER_H */