iris: Initial import of resolve code
authorKenneth Graunke <kenneth@whitecape.org>
Fri, 7 Dec 2018 19:54:16 +0000 (11:54 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 21 Feb 2019 18:26:12 +0000 (10:26 -0800)
src/gallium/drivers/iris/iris_blit.c
src/gallium/drivers/iris/iris_resolve.c
src/gallium/drivers/iris/iris_resource.c
src/gallium/drivers/iris/iris_resource.h
src/gallium/drivers/iris/iris_state.c

index d36b998bef4477668d4fe29b1551a9232449e340..b2a01df0690ec0bc5798bfd87bee4ed3bcbbb62a 100644 (file)
@@ -239,7 +239,17 @@ iris_blorp_surf_for_resource(struct blorp_surf *surf,
       .aux_usage = aux_usage,
    };
 
-   assert(surf->aux_usage == ISL_AUX_USAGE_NONE);
+   if (aux_usage != ISL_AUX_USAGE_NONE) {
+      surf->aux_surf = &res->aux.surf;
+      surf->aux_addr = (struct blorp_address) {
+         .buffer = res->aux.bo,
+         .offset = res->aux.offset,
+         .reloc_flags = is_render_target ? EXEC_OBJECT_WRITE : 0,
+         .mocs = I915_MOCS_CACHED,
+      };
+   }
+
+   // XXX: ASTC
 }
 
 /**
@@ -255,6 +265,8 @@ iris_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
    struct iris_screen *screen = (struct iris_screen *)ctx->screen;
    const struct gen_device_info *devinfo = &screen->devinfo;
    enum blorp_batch_flags blorp_flags = 0;
+   struct iris_resource *src_res = (void *) info->src.resource;
+   struct iris_resource *dst_res = (void *) info->dst.resource;
 
    /* We don't support color masking. */
    assert((info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA ||
@@ -268,18 +280,38 @@ iris_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
          blorp_flags |= BLORP_BATCH_PREDICATE_ENABLE;
    }
 
-   struct blorp_surf src_surf, dst_surf;
-   iris_blorp_surf_for_resource(&src_surf, info->src.resource,
-                                ISL_AUX_USAGE_NONE, false);
-   iris_blorp_surf_for_resource(&dst_surf, info->dst.resource,
-                                ISL_AUX_USAGE_NONE, true);
-
    struct iris_format_info src_fmt =
       iris_format_for_usage(devinfo, info->src.format,
                             ISL_SURF_USAGE_TEXTURE_BIT);
+   enum isl_aux_usage src_aux_usage =
+      iris_resource_texture_aux_usage(ice, src_res, src_fmt.fmt, 0);
+
+   if (src_aux_usage == ISL_AUX_USAGE_HIZ)
+      src_aux_usage = ISL_AUX_USAGE_NONE;
+
+   bool src_clear_supported = src_aux_usage != ISL_AUX_USAGE_NONE &&
+                              src_res->surf.format == src_fmt.fmt;
+
+   iris_resource_prepare_access(ice, src_res, info->src.level, 1,
+                                info->src.box.z, info->src.box.depth,
+                                src_aux_usage, src_clear_supported);
+
    struct iris_format_info dst_fmt =
       iris_format_for_usage(devinfo, info->dst.format,
                             ISL_SURF_USAGE_RENDER_TARGET_BIT);
+   enum isl_aux_usage dst_aux_usage =
+      iris_resource_render_aux_usage(ice, dst_res, dst_fmt.fmt, false, false);
+   bool dst_clear_supported = dst_aux_usage != ISL_AUX_USAGE_NONE;
+
+   struct blorp_surf src_surf, dst_surf;
+   iris_blorp_surf_for_resource(&src_surf, info->src.resource,
+                                ISL_AUX_USAGE_NONE, false);
+   iris_blorp_surf_for_resource(&dst_surf, info->dst.resource,
+                                ISL_AUX_USAGE_NONE, true);
+
+   iris_resource_prepare_access(ice, dst_res, info->dst.level, 1, 
+                                info->dst.box.z, info->dst.box.depth,
+                                dst_aux_usage, dst_clear_supported);
 
    float src_x0 = info->src.box.x;
    float src_x1 = info->src.box.x + info->src.box.width;
@@ -403,6 +435,9 @@ iris_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
 
    blorp_batch_finish(&blorp_batch);
 
+   iris_resource_finish_write(ice, dst_res, info->dst.level, info->dst.box.z,
+                              info->dst.box.depth, dst_aux_usage);
+
    iris_flush_and_dirty_for_history(ice, batch, (struct iris_resource *)
                                     info->dst.resource);
 }
index 737bcfe0e90fb26cb1b6b9a0e1e0b2c84f154234..9fc32fc04825b8ac4833dc25bd9d2b22803fad73 100644 (file)
@@ -286,3 +286,857 @@ iris_depth_cache_add_bo(struct iris_batch *batch, struct iris_bo *bo)
 {
    _mesa_set_add_pre_hashed(batch->cache.depth, bo->hash, bo);
 }
+
+/**
+ * Return true if the format that will be used to access the resource is
+ * CCS_E-compatible with the resource's linear/non-sRGB format.
+ *
+ * Why use the linear format?  Well, although the resourcemay be specified
+ * with an sRGB format, the usage of that color space/format can be toggled.
+ * Since our HW tends to support more linear formats than sRGB ones, we use
+ * this format variant for check for CCS_E compatibility.
+ */
+static bool
+format_ccs_e_compat_with_resource(const struct gen_device_info *devinfo,
+                                  const struct iris_resource *res,
+                                  enum isl_format access_format)
+{
+   assert(res->aux.usage == ISL_AUX_USAGE_CCS_E);
+
+   enum isl_format isl_format = isl_format_srgb_to_linear(res->surf.format);
+   return isl_formats_are_ccs_e_compatible(devinfo, isl_format, access_format);
+}
+
+static bool
+sample_with_hiz(const struct gen_device_info *devinfo,
+                const struct iris_resource *res)
+{
+   if (!devinfo->has_sample_with_hiz)
+      return false;
+
+   if (res->aux.usage != ISL_AUX_USAGE_HIZ)
+      return false;
+
+   /* It seems the hardware won't fallback to the depth buffer if some of the
+    * mipmap levels aren't available in the HiZ buffer. So we need all levels
+    * of the texture to be HiZ enabled.
+    */
+   for (unsigned level = 0; level < res->surf.levels; ++level) {
+      if (!iris_resource_level_has_hiz(res, level))
+         return false;
+   }
+
+   /* If compressed multisampling is enabled, then we use it for the auxiliary
+    * buffer instead.
+    *
+    * From the BDW PRM (Volume 2d: Command Reference: Structures
+    *                   RENDER_SURFACE_STATE.AuxiliarySurfaceMode):
+    *
+    *  "If this field is set to AUX_HIZ, Number of Multisamples must be
+    *   MULTISAMPLECOUNT_1, and Surface Type cannot be SURFTYPE_3D.
+    *
+    * There is no such blurb for 1D textures, but there is sufficient evidence
+    * that this is broken on SKL+.
+    */
+   // XXX: i965 disables this for arrays too, is that reasonable?
+   return res->surf.samples == 1 && res->surf.dim == ISL_SURF_DIM_2D;
+}
+
+/**
+ * Does the resource's slice have hiz enabled?
+ */
+bool
+iris_resource_level_has_hiz(const struct iris_resource *res, uint32_t level)
+{
+   iris_resource_check_level_layer(res, level, 0);
+   // return res->level[level].has_hiz;
+   return false;
+}
+
+/** \brief Assert that the level and layer are valid for the resource. */
+void
+iris_resource_check_level_layer(UNUSED const struct iris_resource *res,
+                                UNUSED uint32_t level, UNUSED uint32_t layer)
+{
+   assert(level < res->surf.levels);
+   assert(layer < util_num_layers(&res->base, level));
+}
+
+static inline uint32_t
+miptree_level_range_length(const struct iris_resource *res,
+                           uint32_t start_level, uint32_t num_levels)
+{
+   assert(start_level < res->surf.levels);
+
+   if (num_levels == INTEL_REMAINING_LAYERS)
+      num_levels = res->surf.levels;
+
+   /* Check for overflow */
+   assert(start_level + num_levels >= start_level);
+   assert(start_level + num_levels <= res->surf.levels);
+
+   return num_levels;
+}
+
+static inline uint32_t
+miptree_layer_range_length(const struct iris_resource *res, uint32_t level,
+                           uint32_t start_layer, uint32_t num_layers)
+{
+   assert(level <= res->base.last_level);
+
+   const uint32_t total_num_layers = iris_get_num_logical_layers(res, level);
+   assert(start_layer < total_num_layers);
+   if (num_layers == INTEL_REMAINING_LAYERS)
+      num_layers = total_num_layers - start_layer;
+   /* Check for overflow */
+   assert(start_layer + num_layers >= start_layer);
+   assert(start_layer + num_layers <= total_num_layers);
+
+   return num_layers;
+}
+
+static bool
+has_color_unresolved(const struct iris_resource *res,
+                     unsigned start_level, unsigned num_levels,
+                     unsigned start_layer, unsigned num_layers)
+{
+   if (!res->aux.bo)
+      return false;
+
+   /* Clamp the level range to fit the resource */
+   num_levels = miptree_level_range_length(res, start_level, num_levels);
+
+   for (uint32_t l = 0; l < num_levels; l++) {
+      const uint32_t level = start_level + l;
+      const uint32_t level_layers =
+         miptree_layer_range_length(res, level, start_layer, num_layers);
+      for (unsigned a = 0; a < level_layers; a++) {
+         enum isl_aux_state aux_state =
+            iris_resource_get_aux_state(res, level, start_layer + a);
+         assert(aux_state != ISL_AUX_STATE_AUX_INVALID);
+         if (aux_state != ISL_AUX_STATE_PASS_THROUGH)
+            return true;
+      }
+   }
+
+   return false;
+}
+
+static enum isl_aux_op
+get_ccs_d_resolve_op(enum isl_aux_state aux_state,
+                     enum isl_aux_usage aux_usage,
+                     bool fast_clear_supported)
+{
+   assert(aux_usage == ISL_AUX_USAGE_NONE || aux_usage == ISL_AUX_USAGE_CCS_D);
+
+   const bool ccs_supported = aux_usage == ISL_AUX_USAGE_CCS_D;
+
+   assert(ccs_supported == fast_clear_supported);
+
+   switch (aux_state) {
+   case ISL_AUX_STATE_CLEAR:
+   case ISL_AUX_STATE_PARTIAL_CLEAR:
+      if (!ccs_supported)
+         return ISL_AUX_OP_FULL_RESOLVE;
+      else
+         return ISL_AUX_OP_NONE;
+
+   case ISL_AUX_STATE_PASS_THROUGH:
+      return ISL_AUX_OP_NONE;
+
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_AUX_INVALID:
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      break;
+   }
+
+   unreachable("Invalid aux state for CCS_D");
+}
+
+static enum isl_aux_op
+get_ccs_e_resolve_op(enum isl_aux_state aux_state,
+                     enum isl_aux_usage aux_usage,
+                     bool fast_clear_supported)
+{
+   /* CCS_E surfaces can be accessed as CCS_D if we're careful. */
+   assert(aux_usage == ISL_AUX_USAGE_NONE ||
+          aux_usage == ISL_AUX_USAGE_CCS_D ||
+          aux_usage == ISL_AUX_USAGE_CCS_E);
+
+   if (aux_usage == ISL_AUX_USAGE_CCS_D)
+      assert(fast_clear_supported);
+
+   switch (aux_state) {
+   case ISL_AUX_STATE_CLEAR:
+   case ISL_AUX_STATE_PARTIAL_CLEAR:
+      if (fast_clear_supported)
+         return ISL_AUX_OP_NONE;
+      else if (aux_usage == ISL_AUX_USAGE_CCS_E)
+         return ISL_AUX_OP_PARTIAL_RESOLVE;
+      else
+         return ISL_AUX_OP_FULL_RESOLVE;
+
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      if (aux_usage != ISL_AUX_USAGE_CCS_E)
+         return ISL_AUX_OP_FULL_RESOLVE;
+      else if (!fast_clear_supported)
+         return ISL_AUX_OP_PARTIAL_RESOLVE;
+      else
+         return ISL_AUX_OP_NONE;
+
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      if (aux_usage != ISL_AUX_USAGE_CCS_E)
+         return ISL_AUX_OP_FULL_RESOLVE;
+      else
+         return ISL_AUX_OP_NONE;
+
+   case ISL_AUX_STATE_PASS_THROUGH:
+      return ISL_AUX_OP_NONE;
+
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_AUX_INVALID:
+      break;
+   }
+
+   unreachable("Invalid aux state for CCS_E");
+}
+
+static void
+iris_resource_prepare_ccs_access(struct iris_context *ice,
+                                 struct iris_resource *res,
+                                 uint32_t level, uint32_t layer,
+                                 enum isl_aux_usage aux_usage,
+                                 bool fast_clear_supported)
+{
+   enum isl_aux_state aux_state = iris_resource_get_aux_state(res, level, layer);
+
+   enum isl_aux_op resolve_op;
+   if (res->aux.usage == ISL_AUX_USAGE_CCS_E) {
+      resolve_op = get_ccs_e_resolve_op(aux_state, aux_usage,
+                                        fast_clear_supported);
+   } else {
+      assert(res->aux.usage == ISL_AUX_USAGE_CCS_D);
+      resolve_op = get_ccs_d_resolve_op(aux_state, aux_usage,
+                                        fast_clear_supported);
+   }
+
+   if (resolve_op != ISL_AUX_OP_NONE) {
+      // XXX: iris_blorp_resolve_color(ice, res, level, layer, resolve_op);
+
+      switch (resolve_op) {
+      case ISL_AUX_OP_FULL_RESOLVE:
+         /* The CCS full resolve operation destroys the CCS and sets it to the
+          * pass-through state.  (You can also think of this as being both a
+          * resolve and an ambiguate in one operation.)
+          */
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_PASS_THROUGH);
+         break;
+
+      case ISL_AUX_OP_PARTIAL_RESOLVE:
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_NO_CLEAR);
+         break;
+
+      default:
+         unreachable("Invalid resolve op");
+      }
+   }
+}
+
+static void
+iris_resource_finish_ccs_write(struct iris_context *ice,
+                               struct iris_resource *res,
+                               uint32_t level, uint32_t layer,
+                               enum isl_aux_usage aux_usage)
+{
+   assert(aux_usage == ISL_AUX_USAGE_NONE ||
+          aux_usage == ISL_AUX_USAGE_CCS_D ||
+          aux_usage == ISL_AUX_USAGE_CCS_E);
+
+   enum isl_aux_state aux_state =
+      iris_resource_get_aux_state(res, level, layer);
+
+   if (res->aux.usage == ISL_AUX_USAGE_CCS_E) {
+      switch (aux_state) {
+      case ISL_AUX_STATE_CLEAR:
+      case ISL_AUX_STATE_PARTIAL_CLEAR:
+         assert(aux_usage == ISL_AUX_USAGE_CCS_E ||
+                aux_usage == ISL_AUX_USAGE_CCS_D);
+
+         if (aux_usage == ISL_AUX_USAGE_CCS_E) {
+            iris_resource_set_aux_state(res, level, layer, 1,
+                                        ISL_AUX_STATE_COMPRESSED_CLEAR);
+         } else if (aux_state != ISL_AUX_STATE_PARTIAL_CLEAR) {
+            iris_resource_set_aux_state(res, level, layer, 1,
+                                        ISL_AUX_STATE_PARTIAL_CLEAR);
+         }
+         break;
+
+      case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+         assert(aux_usage == ISL_AUX_USAGE_CCS_E);
+         break; /* Nothing to do */
+
+      case ISL_AUX_STATE_PASS_THROUGH:
+         if (aux_usage == ISL_AUX_USAGE_CCS_E) {
+            iris_resource_set_aux_state(res, level, layer, 1,
+                                        ISL_AUX_STATE_COMPRESSED_NO_CLEAR);
+         } else {
+            /* Nothing to do */
+         }
+         break;
+
+      case ISL_AUX_STATE_RESOLVED:
+      case ISL_AUX_STATE_AUX_INVALID:
+         unreachable("Invalid aux state for CCS_E");
+      }
+   } else {
+      assert(res->aux.usage == ISL_AUX_USAGE_CCS_D);
+      /* CCS_D is a bit simpler */
+      switch (aux_state) {
+      case ISL_AUX_STATE_CLEAR:
+         assert(aux_usage == ISL_AUX_USAGE_CCS_D);
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_PARTIAL_CLEAR);
+         break;
+
+      case ISL_AUX_STATE_PARTIAL_CLEAR:
+         assert(aux_usage == ISL_AUX_USAGE_CCS_D);
+         break; /* Nothing to do */
+
+      case ISL_AUX_STATE_PASS_THROUGH:
+         /* Nothing to do */
+         break;
+
+      case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      case ISL_AUX_STATE_RESOLVED:
+      case ISL_AUX_STATE_AUX_INVALID:
+         unreachable("Invalid aux state for CCS_D");
+      }
+   }
+}
+
+static void
+iris_resource_prepare_mcs_access(struct iris_context *ice,
+                                 struct iris_resource *res,
+                                 uint32_t layer,
+                                 enum isl_aux_usage aux_usage,
+                                 bool fast_clear_supported)
+{
+   assert(aux_usage == ISL_AUX_USAGE_MCS);
+
+   switch (iris_resource_get_aux_state(res, 0, layer)) {
+   case ISL_AUX_STATE_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      if (!fast_clear_supported) {
+         // XXX: iris_blorp_mcs_partial_resolve(ice, res, layer, 1);
+         iris_resource_set_aux_state(res, 0, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_NO_CLEAR);
+      }
+      break;
+
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      break; /* Nothing to do */
+
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_PASS_THROUGH:
+   case ISL_AUX_STATE_AUX_INVALID:
+   case ISL_AUX_STATE_PARTIAL_CLEAR:
+      unreachable("Invalid aux state for MCS");
+   }
+}
+
+static void
+iris_resource_finish_mcs_write(struct iris_context *ice,
+                               struct iris_resource *res,
+                               uint32_t layer,
+                               enum isl_aux_usage aux_usage)
+{
+   assert(aux_usage == ISL_AUX_USAGE_MCS);
+
+   switch (iris_resource_get_aux_state(res, 0, layer)) {
+   case ISL_AUX_STATE_CLEAR:
+      iris_resource_set_aux_state(res, 0, layer, 1,
+                                  ISL_AUX_STATE_COMPRESSED_CLEAR);
+      break;
+
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      break; /* Nothing to do */
+
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_PASS_THROUGH:
+   case ISL_AUX_STATE_AUX_INVALID:
+   case ISL_AUX_STATE_PARTIAL_CLEAR:
+      unreachable("Invalid aux state for MCS");
+   }
+}
+
+static void
+iris_resource_prepare_hiz_access(struct iris_context *ice,
+                                 struct iris_resource *res,
+                                 uint32_t level, uint32_t layer,
+                                 enum isl_aux_usage aux_usage,
+                                 bool fast_clear_supported)
+{
+   assert(aux_usage == ISL_AUX_USAGE_NONE || aux_usage == ISL_AUX_USAGE_HIZ);
+
+   enum isl_aux_op hiz_op = ISL_AUX_OP_NONE;
+   switch (iris_resource_get_aux_state(res, level, layer)) {
+   case ISL_AUX_STATE_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      if (aux_usage != ISL_AUX_USAGE_HIZ || !fast_clear_supported)
+         hiz_op = ISL_AUX_OP_FULL_RESOLVE;
+      break;
+
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      if (aux_usage != ISL_AUX_USAGE_HIZ)
+         hiz_op = ISL_AUX_OP_FULL_RESOLVE;
+      break;
+
+   case ISL_AUX_STATE_PASS_THROUGH:
+   case ISL_AUX_STATE_RESOLVED:
+      break;
+
+   case ISL_AUX_STATE_AUX_INVALID:
+      if (aux_usage == ISL_AUX_USAGE_HIZ)
+         hiz_op = ISL_AUX_OP_AMBIGUATE;
+      break;
+
+   case ISL_AUX_STATE_PARTIAL_CLEAR:
+      unreachable("Invalid HiZ state");
+   }
+
+   if (hiz_op != ISL_AUX_OP_NONE) {
+      // XXX: HiZ
+      //intel_hiz_exec(ice, res, level, layer, 1, hiz_op);
+
+      switch (hiz_op) {
+      case ISL_AUX_OP_FULL_RESOLVE:
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_RESOLVED);
+         break;
+
+      case ISL_AUX_OP_AMBIGUATE:
+         /* The HiZ resolve operation is actually an ambiguate */
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_PASS_THROUGH);
+         break;
+
+      default:
+         unreachable("Invalid HiZ op");
+      }
+   }
+}
+
+static void
+iris_resource_finish_hiz_write(struct iris_context *ice,
+                               struct iris_resource *res,
+                               uint32_t level, uint32_t layer,
+                               enum isl_aux_usage aux_usage)
+{
+   assert(aux_usage == ISL_AUX_USAGE_NONE || aux_usage == ISL_AUX_USAGE_HIZ);
+
+   switch (iris_resource_get_aux_state(res, level, layer)) {
+   case ISL_AUX_STATE_CLEAR:
+      assert(aux_usage == ISL_AUX_USAGE_HIZ);
+      iris_resource_set_aux_state(res, level, layer, 1,
+                                  ISL_AUX_STATE_COMPRESSED_CLEAR);
+      break;
+
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      assert(aux_usage == ISL_AUX_USAGE_HIZ);
+      break; /* Nothing to do */
+
+   case ISL_AUX_STATE_RESOLVED:
+      if (aux_usage == ISL_AUX_USAGE_HIZ) {
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_NO_CLEAR);
+      } else {
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_AUX_INVALID);
+      }
+      break;
+
+   case ISL_AUX_STATE_PASS_THROUGH:
+      if (aux_usage == ISL_AUX_USAGE_HIZ) {
+         iris_resource_set_aux_state(res, level, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_NO_CLEAR);
+      }
+      break;
+
+   case ISL_AUX_STATE_AUX_INVALID:
+      assert(aux_usage != ISL_AUX_USAGE_HIZ);
+      break;
+
+   case ISL_AUX_STATE_PARTIAL_CLEAR:
+      unreachable("Invalid HiZ state");
+   }
+}
+
+void
+iris_resource_prepare_access(struct iris_context *ice,
+                             struct iris_resource *res,
+                             uint32_t start_level, uint32_t num_levels,
+                             uint32_t start_layer, uint32_t num_layers,
+                             enum isl_aux_usage aux_usage,
+                             bool fast_clear_supported)
+{
+   num_levels = miptree_level_range_length(res, start_level, num_levels);
+
+   switch (res->aux.usage) {
+   case ISL_AUX_USAGE_NONE:
+      /* Nothing to do */
+      break;
+
+   case ISL_AUX_USAGE_MCS:
+      assert(start_level == 0 && num_levels == 1);
+      const uint32_t level_layers =
+         miptree_layer_range_length(res, 0, start_layer, num_layers);
+      for (uint32_t a = 0; a < level_layers; a++) {
+         iris_resource_prepare_mcs_access(ice, res, start_layer + a,
+                                          aux_usage, fast_clear_supported);
+      }
+      break;
+
+   case ISL_AUX_USAGE_CCS_D:
+   case ISL_AUX_USAGE_CCS_E:
+      for (uint32_t l = 0; l < num_levels; l++) {
+         const uint32_t level = start_level + l;
+         const uint32_t level_layers =
+            miptree_layer_range_length(res, level, start_layer, num_layers);
+         for (uint32_t a = 0; a < level_layers; a++) {
+            iris_resource_prepare_ccs_access(ice, res, level,
+                                             start_layer + a,
+                                             aux_usage, fast_clear_supported);
+         }
+      }
+      break;
+
+   case ISL_AUX_USAGE_HIZ:
+      for (uint32_t l = 0; l < num_levels; l++) {
+         const uint32_t level = start_level + l;
+         if (!iris_resource_level_has_hiz(res, level))
+            continue;
+
+         const uint32_t level_layers =
+            miptree_layer_range_length(res, level, start_layer, num_layers);
+         for (uint32_t a = 0; a < level_layers; a++) {
+            iris_resource_prepare_hiz_access(ice, res, level, start_layer + a,
+                                             aux_usage, fast_clear_supported);
+         }
+      }
+      break;
+
+   default:
+      unreachable("Invalid aux usage");
+   }
+}
+
+void
+iris_resource_finish_write(struct iris_context *ice,
+                           struct iris_resource *res, uint32_t level,
+                           uint32_t start_layer, uint32_t num_layers,
+                           enum isl_aux_usage aux_usage)
+{
+   num_layers = miptree_layer_range_length(res, level, start_layer, num_layers);
+
+   switch (res->aux.usage) {
+   case ISL_AUX_USAGE_NONE:
+      break;
+
+   case ISL_AUX_USAGE_MCS:
+      for (uint32_t a = 0; a < num_layers; a++) {
+         iris_resource_finish_mcs_write(ice, res, start_layer + a,
+                                        aux_usage);
+      }
+      break;
+
+   case ISL_AUX_USAGE_CCS_D:
+   case ISL_AUX_USAGE_CCS_E:
+      for (uint32_t a = 0; a < num_layers; a++) {
+         iris_resource_finish_ccs_write(ice, res, level, start_layer + a,
+                                        aux_usage);
+      }
+      break;
+
+   case ISL_AUX_USAGE_HIZ:
+      if (!iris_resource_level_has_hiz(res, level))
+         return;
+
+      for (uint32_t a = 0; a < num_layers; a++) {
+         iris_resource_finish_hiz_write(ice, res, level, start_layer + a,
+                                        aux_usage);
+      }
+      break;
+
+   default:
+      unreachable("Invavlid aux usage");
+   }
+}
+
+enum isl_aux_state
+iris_resource_get_aux_state(const struct iris_resource *res,
+                            uint32_t level, uint32_t layer)
+{
+   iris_resource_check_level_layer(res, level, layer);
+
+   if (res->surf.usage & ISL_SURF_USAGE_DEPTH_BIT) {
+      assert(iris_resource_level_has_hiz(res, level));
+   } else if (res->surf.usage & ISL_SURF_USAGE_STENCIL_BIT) {
+      unreachable("Cannot get aux state for stencil");
+   } else {
+      assert(res->surf.samples == 1 ||
+             res->surf.msaa_layout == ISL_MSAA_LAYOUT_ARRAY);
+   }
+
+   return res->aux.state[level][layer];
+}
+
+void
+iris_resource_set_aux_state(struct iris_resource *res, uint32_t level,
+                            uint32_t start_layer, uint32_t num_layers,
+                            enum isl_aux_state aux_state)
+{
+   num_layers = miptree_layer_range_length(res, level, start_layer, num_layers);
+
+   if (res->surf.usage & ISL_SURF_USAGE_DEPTH_BIT) {
+      assert(iris_resource_level_has_hiz(res, level));
+   } else if (res->surf.usage & ISL_SURF_USAGE_STENCIL_BIT) {
+      unreachable("Cannot set aux state for stencil");
+   } else {
+      assert(res->surf.samples == 1 ||
+             res->surf.msaa_layout == ISL_MSAA_LAYOUT_ARRAY);
+   }
+
+   for (unsigned a = 0; a < num_layers; a++) {
+      if (res->aux.state[level][start_layer + a] != aux_state) {
+         res->aux.state[level][start_layer + a] = aux_state;
+         // XXX: dirty works differently
+         // brw->ctx.NewDriverState |= BRW_NEW_AUX_STATE;
+      }
+   }
+}
+
+/* On Gen9 color buffers may be compressed by the hardware (lossless
+ * compression). There are, however, format restrictions and care needs to be
+ * taken that the sampler engine is capable for re-interpreting a buffer with
+ * format different the buffer was originally written with.
+ *
+ * For example, SRGB formats are not compressible and the sampler engine isn't
+ * capable of treating RGBA_UNORM as SRGB_ALPHA. In such a case the underlying
+ * color buffer needs to be resolved so that the sampling surface can be
+ * sampled as non-compressed (i.e., without the auxiliary MCS buffer being
+ * set).
+ */
+static bool
+can_texture_with_ccs(const struct gen_device_info *devinfo,
+                     struct pipe_debug_callback *dbg,
+                     const struct iris_resource *res,
+                     enum isl_format view_format)
+{
+   if (res->aux.usage != ISL_AUX_USAGE_CCS_E)
+      return false;
+
+   if (!format_ccs_e_compat_with_resource(devinfo, res, view_format)) {
+      const struct isl_format_layout *res_fmtl =
+         isl_format_get_layout(res->surf.format);
+      const struct isl_format_layout *view_fmtl =
+         isl_format_get_layout(view_format);
+
+      perf_debug(dbg, "Incompatible sampling format (%s) for CCS (%s)\n",
+                 view_fmtl->name, res_fmtl->name);
+
+      return false;
+   }
+
+   return true;
+}
+
+enum isl_aux_usage
+iris_resource_texture_aux_usage(struct iris_context *ice,
+                                const struct iris_resource *res,
+                                enum isl_format view_format,
+                                enum gen9_astc5x5_wa_tex_type astc5x5_wa_bits)
+{
+   struct iris_screen *screen = (void *) ice->ctx.screen;
+   struct gen_device_info *devinfo = &screen->devinfo;
+
+   assert(devinfo->gen == 9 || astc5x5_wa_bits == 0);
+
+   /* On gen9, ASTC 5x5 textures cannot live in the sampler cache along side
+    * CCS or HiZ compressed textures.  See gen9_apply_astc5x5_wa_flush() for
+    * details.
+    */
+   if ((astc5x5_wa_bits & GEN9_ASTC5X5_WA_TEX_TYPE_ASTC5x5) &&
+       res->aux.usage != ISL_AUX_USAGE_MCS)
+      return ISL_AUX_USAGE_NONE;
+
+   switch (res->aux.usage) {
+   case ISL_AUX_USAGE_HIZ:
+      if (sample_with_hiz(devinfo, res))
+         return ISL_AUX_USAGE_HIZ;
+      break;
+
+   case ISL_AUX_USAGE_MCS:
+      return ISL_AUX_USAGE_MCS;
+
+   case ISL_AUX_USAGE_CCS_D:
+   case ISL_AUX_USAGE_CCS_E:
+      /* If we don't have any unresolved color, report an aux usage of
+       * ISL_AUX_USAGE_NONE.  This way, texturing won't even look at the
+       * aux surface and we can save some bandwidth.
+       */
+      if (!has_color_unresolved(res, 0, INTEL_REMAINING_LEVELS,
+                                0, INTEL_REMAINING_LAYERS))
+         return ISL_AUX_USAGE_NONE;
+
+      if (can_texture_with_ccs(devinfo, &ice->dbg, res, view_format))
+         return ISL_AUX_USAGE_CCS_E;
+      break;
+
+   default:
+      break;
+   }
+
+   return ISL_AUX_USAGE_NONE;
+}
+
+static bool
+isl_formats_are_fast_clear_compatible(enum isl_format a, enum isl_format b)
+{
+   /* On gen8 and earlier, the hardware was only capable of handling 0/1 clear
+    * values so sRGB curve application was a no-op for all fast-clearable
+    * formats.
+    *
+    * On gen9+, the hardware supports arbitrary clear values.  For sRGB clear
+    * values, the hardware interprets the floats, not as what would be
+    * returned from the sampler (or written by the shader), but as being
+    * between format conversion and sRGB curve application.  This means that
+    * we can switch between sRGB and UNORM without having to whack the clear
+    * color.
+    */
+   return isl_format_srgb_to_linear(a) == isl_format_srgb_to_linear(b);
+}
+
+void
+iris_resource_prepare_texture(struct iris_context *ice,
+                              struct iris_resource *res,
+                              enum isl_format view_format,
+                              uint32_t start_level, uint32_t num_levels,
+                              uint32_t start_layer, uint32_t num_layers,
+                              enum gen9_astc5x5_wa_tex_type astc5x5_wa_bits)
+{
+   enum isl_aux_usage aux_usage =
+      iris_resource_texture_aux_usage(ice, res, view_format, astc5x5_wa_bits);
+
+   bool clear_supported = aux_usage != ISL_AUX_USAGE_NONE;
+
+   /* Clear color is specified as ints or floats and the conversion is done by
+    * the sampler.  If we have a texture view, we would have to perform the
+    * clear color conversion manually.  Just disable clear color.
+    */
+   if (!isl_formats_are_fast_clear_compatible(res->surf.format, view_format))
+      clear_supported = false;
+
+   iris_resource_prepare_access(ice, res, start_level, num_levels,
+                                start_layer, num_layers,
+                                aux_usage, clear_supported);
+}
+
+void
+iris_resource_prepare_image(struct iris_context *ice,
+                            struct iris_resource *res)
+{
+   /* The data port doesn't understand any compression */
+   iris_resource_prepare_access(ice, res, 0, INTEL_REMAINING_LEVELS,
+                                0, INTEL_REMAINING_LAYERS,
+                                ISL_AUX_USAGE_NONE, false);
+}
+
+enum isl_aux_usage
+iris_resource_render_aux_usage(struct iris_context *ice,
+                               struct iris_resource *res,
+                               enum isl_format render_format,
+                               bool blend_enabled,
+                               bool draw_aux_disabled)
+{
+   struct iris_screen *screen = (void *) ice->ctx.screen;
+   struct gen_device_info *devinfo = &screen->devinfo;
+
+   if (draw_aux_disabled)
+      return ISL_AUX_USAGE_NONE;
+
+   switch (res->aux.usage) {
+   case ISL_AUX_USAGE_MCS:
+      return ISL_AUX_USAGE_MCS;
+
+   case ISL_AUX_USAGE_CCS_D:
+   case ISL_AUX_USAGE_CCS_E:
+      /* Gen9+ hardware technically supports non-0/1 clear colors with sRGB
+       * formats.  However, there are issues with blending where it doesn't
+       * properly apply the sRGB curve to the clear color when blending.
+       */
+      /* XXX:
+      if (devinfo->gen >= 9 && blend_enabled &&
+          isl_format_is_srgb(render_format) &&
+          !isl_color_value_is_zero_one(res->fast_clear_color, render_format))
+         return ISL_AUX_USAGE_NONE;
+         */
+
+      if (res->aux.usage == ISL_AUX_USAGE_CCS_E &&
+          format_ccs_e_compat_with_resource(devinfo, res, render_format))
+         return ISL_AUX_USAGE_CCS_E;
+
+      /* Otherwise, we have to fall back to CCS_D */
+      return ISL_AUX_USAGE_CCS_D;
+
+   default:
+      return ISL_AUX_USAGE_NONE;
+   }
+}
+
+void
+iris_resource_prepare_render(struct iris_context *ice,
+                             struct iris_resource *res, uint32_t level,
+                             uint32_t start_layer, uint32_t layer_count,
+                             enum isl_aux_usage aux_usage)
+{
+   iris_resource_prepare_access(ice, res, level, 1, start_layer, layer_count,
+                                aux_usage, aux_usage != ISL_AUX_USAGE_NONE);
+}
+
+void
+iris_resource_finish_render(struct iris_context *ice,
+                            struct iris_resource *res, uint32_t level,
+                            uint32_t start_layer, uint32_t layer_count,
+                            enum isl_aux_usage aux_usage)
+{
+   iris_resource_finish_write(ice, res, level, start_layer, layer_count,
+                              aux_usage);
+}
+
+void
+iris_resource_prepare_depth(struct iris_context *ice,
+                            struct iris_resource *res, uint32_t level,
+                            uint32_t start_layer, uint32_t layer_count)
+{
+   iris_resource_prepare_access(ice, res, level, 1, start_layer, layer_count,
+                                res->aux.usage, res->aux.bo != NULL);
+}
+
+void
+iris_resource_finish_depth(struct iris_context *ice,
+                           struct iris_resource *res, uint32_t level,
+                           uint32_t start_layer, uint32_t layer_count,
+                           bool depth_written)
+{
+   if (depth_written) {
+      iris_resource_finish_write(ice, res, level, start_layer, layer_count,
+                                 res->aux.usage);
+   }
+}
index b474093956df12b0c642a34589f785bf3e85b442..349e4efe02227f84e5ec85cdfc82ee4ef04243ca 100644 (file)
@@ -196,12 +196,15 @@ iris_get_depth_stencil_resources(struct pipe_resource *res,
    }
 }
 
-static void
+void
 iris_resource_disable_aux(struct iris_resource *res)
 {
    iris_bo_unreference(res->aux.bo);
    free(res->aux.state);
 
+   // XXX: clear color BO
+   // XXX: HiZ
+
    res->aux.usage = ISL_AUX_USAGE_NONE;
    res->aux.surf.size_B = 0;
    res->aux.bo = NULL;
index 0424ea253e806a1fa25d07ba2128a8ae7f7f273c..c17ed42ada2d2a14e32ac544c711a356e67ff6f0 100644 (file)
@@ -41,6 +41,11 @@ struct iris_format_info {
 #define IRIS_RESOURCE_FLAG_SURFACE_MEMZONE (PIPE_RESOURCE_FLAG_DRV_PRIV << 1)
 #define IRIS_RESOURCE_FLAG_DYNAMIC_MEMZONE (PIPE_RESOURCE_FLAG_DRV_PRIV << 2)
 
+enum gen9_astc5x5_wa_tex_type {
+   GEN9_ASTC5X5_WA_TEX_TYPE_ASTC5x5 = 1 << 0,
+   GEN9_ASTC5X5_WA_TEX_TYPE_AUX     = 1 << 1,
+};
+
 /**
  * Resources represent a GPU buffer object or image (mipmap tree).
  *
@@ -195,4 +200,147 @@ void iris_flush_and_dirty_for_history(struct iris_context *ice,
 unsigned iris_get_num_logical_layers(const struct iris_resource *res,
                                      unsigned level);
 
+void iris_resource_disable_aux(struct iris_resource *res);
+
+#define INTEL_REMAINING_LAYERS UINT32_MAX
+#define INTEL_REMAINING_LEVELS UINT32_MAX
+
+/**
+ * Prepare a miptree for access
+ *
+ * This function should be called prior to any access to miptree in order to
+ * perform any needed resolves.
+ *
+ * \param[in]  start_level    The first mip level to be accessed
+ *
+ * \param[in]  num_levels     The number of miplevels to be accessed or
+ *                            INTEL_REMAINING_LEVELS to indicate every level
+ *                            above start_level will be accessed
+ *
+ * \param[in]  start_layer    The first array slice or 3D layer to be accessed
+ *
+ * \param[in]  num_layers     The number of array slices or 3D layers be
+ *                            accessed or INTEL_REMAINING_LAYERS to indicate
+ *                            every layer above start_layer will be accessed
+ *
+ * \param[in]  aux_supported  Whether or not the access will support the
+ *                            miptree's auxiliary compression format;  this
+ *                            must be false for uncompressed miptrees
+ *
+ * \param[in]  fast_clear_supported Whether or not the access will support
+ *                                  fast clears in the miptree's auxiliary
+ *                                  compression format
+ */
+void
+iris_resource_prepare_access(struct iris_context *ice,
+                             struct iris_resource *res,
+                             uint32_t start_level, uint32_t num_levels,
+                             uint32_t start_layer, uint32_t num_layers,
+                             enum isl_aux_usage aux_usage,
+                             bool fast_clear_supported);
+
+/**
+ * Complete a write operation
+ *
+ * This function should be called after any operation writes to a miptree.
+ * This will update the miptree's compression state so that future resolves
+ * happen correctly.  Technically, this function can be called before the
+ * write occurs but the caller must ensure that they don't interlace
+ * iris_resource_prepare_access and iris_resource_finish_write calls to
+ * overlapping layer/level ranges.
+ *
+ * \param[in]  level             The mip level that was written
+ *
+ * \param[in]  start_layer       The first array slice or 3D layer written
+ *
+ * \param[in]  num_layers        The number of array slices or 3D layers
+ *                               written or INTEL_REMAINING_LAYERS to indicate
+ *                               every layer above start_layer was written
+ *
+ * \param[in]  written_with_aux  Whether or not the write was done with
+ *                               auxiliary compression enabled
+ */
+void
+iris_resource_finish_write(struct iris_context *ice,
+                           struct iris_resource *res, uint32_t level,
+                           uint32_t start_layer, uint32_t num_layers,
+                           enum isl_aux_usage aux_usage);
+
+/** Get the auxiliary compression state of a miptree slice */
+enum isl_aux_state
+iris_resource_get_aux_state(const struct iris_resource *res,
+                            uint32_t level, uint32_t layer);
+
+/**
+ * Set the auxiliary compression state of a miptree slice range
+ *
+ * This function directly sets the auxiliary compression state of a slice
+ * range of a miptree.  It only modifies data structures and does not do any
+ * resolves.  This should only be called by code which directly performs
+ * compression operations such as fast clears and resolves.  Most code should
+ * use iris_resource_prepare_access or iris_resource_finish_write.
+ */
+void
+iris_resource_set_aux_state(struct iris_resource *res, uint32_t level,
+                            uint32_t start_layer, uint32_t num_layers,
+                            enum isl_aux_state aux_state);
+
+/**
+ * Prepare a miptree for raw access
+ *
+ * This helper prepares the miptree for access that knows nothing about any
+ * sort of compression whatsoever.  This is useful when mapping the surface or
+ * using it with the blitter.
+ */
+static inline void
+iris_resource_access_raw(struct iris_context *ice,
+                         struct iris_resource *res,
+                         uint32_t level, uint32_t layer,
+                         bool write)
+{
+   iris_resource_prepare_access(ice, res, level, 1, layer, 1,
+                                ISL_AUX_USAGE_NONE, false);
+   if (write)
+      iris_resource_finish_write(ice, res, level, layer, 1, ISL_AUX_USAGE_NONE);
+}
+
+enum isl_aux_usage iris_resource_texture_aux_usage(struct iris_context *ice,
+                                                   const struct iris_resource *res,
+                                                   enum isl_format view_fmt,
+                                                   enum gen9_astc5x5_wa_tex_type);
+void iris_resource_prepare_texture(struct iris_context *ice,
+                                   struct iris_resource *res,
+                                   enum isl_format view_format,
+                                   uint32_t start_level, uint32_t num_levels,
+                                   uint32_t start_layer, uint32_t num_layers,
+                                   enum gen9_astc5x5_wa_tex_type);
+void iris_resource_prepare_image(struct iris_context *ice,
+                                 struct iris_resource *res);
+
+void iris_resource_check_level_layer(const struct iris_resource *res,
+                                     uint32_t level, uint32_t layer);
+
+bool iris_resource_level_has_hiz(const struct iris_resource *res,
+                                 uint32_t level);
+
+enum isl_aux_usage iris_resource_render_aux_usage(struct iris_context *ice,
+                                                  struct iris_resource *res,
+                                                  enum isl_format render_fmt,
+                                                  bool blend_enabled,
+                                                  bool draw_aux_disabled);
+void iris_resource_prepare_render(struct iris_context *ice,
+                                  struct iris_resource *res, uint32_t level,
+                                  uint32_t start_layer, uint32_t layer_count,
+                                  enum isl_aux_usage aux_usage);
+void iris_resource_finish_render(struct iris_context *ice,
+                                 struct iris_resource *res, uint32_t level,
+                                 uint32_t start_layer, uint32_t layer_count,
+                                 enum isl_aux_usage aux_usage);
+void iris_resource_prepare_depth(struct iris_context *ice,
+                                 struct iris_resource *res, uint32_t level,
+                                 uint32_t start_layer, uint32_t layer_count);
+void iris_resource_finish_depth(struct iris_context *ice,
+                                struct iris_resource *res, uint32_t level,
+                                uint32_t start_layer, uint32_t layer_count,
+                                bool depth_written);
 #endif
index aa16f8517d663d3092aaa8b7b932ffb23f9765de..9ff40a0160b1498f9f3d7222fe227ca392d69e14 100644 (file)
@@ -3778,6 +3778,8 @@ iris_populate_binding_table(struct iris_context *ice,
       return;
    }
 
+   // XXX: use different surface states per aux mode
+
    if (stage == MESA_SHADER_COMPUTE) {
       /* surface for gl_NumWorkGroups */
       struct iris_state_ref *grid_data = &ice->state.grid_size;