i965: Wholesale replace the color resolve tracking code
authorJason Ekstrand <jason.ekstrand@intel.com>
Fri, 26 May 2017 00:18:30 +0000 (17:18 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Thu, 8 Jun 2017 05:18:53 +0000 (22:18 -0700)
This commit reworks the resolve tracking for CCS and MCS to use the new
isl_aux_state enum.  This should provide much more accurate and easy to
reason about tracking.  In order to understand, for instance, the
intel_miptree_prepare_ccs_access function, one only has to go look at
the giant comment for the isl_aux_state enum and follow the arrows.
Unfortunately, there's no good way to split this up without making a
real mess so there are a bunch of changes in here:

 1) We now do partial resolves.  I really have no idea how this ever
    worked before.  So far as I can tell, the only time the old code
    ever did a partial resolve was when it was using CCS_D where a
    partial resolve and a full resolve are the same thing.

 2) We are now tracking 4 states instead of 3 for CCS_E.  In particular,
    we distinguish between compressed with clear and compressed without
    clear.  The end result is that you will never get two partial
    resolves in a row.

 3) The texture view rules are now more correct.  Previously, we would
    only bail if compression was not supported by the destination
    format.  However, this is not actually correct.  Not all format
    pairs are supported for texture views with CCS even if both support
    CCS individually.  Fortunately, ISL has a helper for this.

 4) We are no longer using intel_resolve_map for tracking aux state but
    are instead using a simple array of enum isl_aux_state indexed by
    level and layer.  This is because, now that we're tracking 4
    different states, it's no longer clear which should be the "default"
    and array lookups are faster than linked list searches.

 5) The new code is very assert-happy.  Incorrect transitions will now
    get caught by assertions rather than by rendering corruption.

Reviewed-by: Topi Pohjolainen <topi.pohjolainen@intel.com>
Acked-by: Chad Versace <chadversary@chromium.org>
src/mesa/drivers/dri/i965/intel_mipmap_tree.c
src/mesa/drivers/dri/i965/intel_mipmap_tree.h
src/mesa/drivers/dri/i965/intel_resolve_map.h

index 4a11c8e1d0fdee863b2c5ed4071cf0486752425a..18a83aedb473a57d1939924264bab4670abb02e7 100644 (file)
@@ -328,7 +328,7 @@ intel_miptree_create_layout(struct brw_context *brw,
    mt->aux_disable |= INTEL_AUX_DISABLE_CCS;
    mt->is_scanout = (layout_flags & MIPTREE_LAYOUT_FOR_SCANOUT) != 0;
    exec_list_make_empty(&mt->hiz_map);
-   exec_list_make_empty(&mt->color_resolve_map);
+   mt->aux_state = NULL;
    mt->cpp = _mesa_get_format_bytes(format);
    mt->num_samples = num_samples;
    mt->compressed = _mesa_is_format_compressed(format);
@@ -578,6 +578,46 @@ intel_lower_compressed_format(struct brw_context *brw, mesa_format format)
    }
 }
 
+static enum isl_aux_state **
+create_aux_state_map(struct intel_mipmap_tree *mt,
+                     enum isl_aux_state initial)
+{
+   const uint32_t levels = mt->last_level + 1;
+
+   uint32_t total_slices = 0;
+   for (uint32_t level = 0; level < levels; level++)
+      total_slices += mt->level[level].depth;
+
+   const size_t per_level_array_size = levels * sizeof(enum isl_aux_state *);
+
+   /* We're going to allocate a single chunk of data for both the per-level
+    * reference array and the arrays of aux_state.  This makes cleanup
+    * significantly easier.
+    */
+   const size_t total_size = per_level_array_size +
+                             total_slices * sizeof(enum isl_aux_state);
+   void *data = malloc(total_size);
+   if (data == NULL)
+      return NULL;
+
+   enum isl_aux_state **per_level_arr = data;
+   enum isl_aux_state *s = data + per_level_array_size;
+   for (uint32_t level = 0; level < levels; level++) {
+      per_level_arr[level] = s;
+      for (uint32_t a = 0; a < mt->level[level].depth; a++)
+         *(s++) = initial;
+   }
+   assert((void *)s == data + total_size);
+
+   return per_level_arr;
+}
+
+static void
+free_aux_state_map(enum isl_aux_state **state)
+{
+   free(state);
+}
+
 static struct intel_mipmap_tree *
 miptree_create(struct brw_context *brw,
                GLenum target,
@@ -940,7 +980,7 @@ intel_miptree_release(struct intel_mipmap_tree **mt)
          free((*mt)->mcs_buf);
       }
       intel_resolve_map_clear(&(*mt)->hiz_map);
-      intel_resolve_map_clear(&(*mt)->color_resolve_map);
+      free_aux_state_map((*mt)->aux_state);
 
       intel_miptree_release(&(*mt)->plane[0]);
       intel_miptree_release(&(*mt)->plane[1]);
@@ -1487,27 +1527,31 @@ intel_miptree_alloc_mcs(struct brw_context *brw,
       unreachable("Unrecognized sample count in intel_miptree_alloc_mcs");
    };
 
+   /* Multisampled miptrees are only supported for single level. */
+   assert(mt->first_level == 0);
+   enum isl_aux_state **aux_state =
+      create_aux_state_map(mt, ISL_AUX_STATE_CLEAR);
+   if (!aux_state)
+      return false;
+
    mt->mcs_buf =
       intel_mcs_miptree_buf_create(brw, mt,
                                    format,
                                    mt->logical_width0,
                                    mt->logical_height0,
                                    MIPTREE_LAYOUT_ACCELERATED_UPLOAD);
-   if (!mt->mcs_buf)
+   if (!mt->mcs_buf) {
+      free(aux_state);
       return false;
+   }
 
-   intel_miptree_init_mcs(brw, mt, 0xFF);
+   mt->aux_state = aux_state;
 
-   /* Multisampled miptrees are only supported for single level. */
-   assert(mt->first_level == 0);
-   intel_miptree_set_fast_clear_state(brw, mt, mt->first_level, 0,
-                                      mt->logical_depth0,
-                                      INTEL_FAST_CLEAR_STATE_CLEAR);
+   intel_miptree_init_mcs(brw, mt, 0xFF);
 
    return true;
 }
 
-
 bool
 intel_miptree_alloc_non_msrt_mcs(struct brw_context *brw,
                                  struct intel_mipmap_tree *mt,
@@ -1533,6 +1577,13 @@ intel_miptree_alloc_non_msrt_mcs(struct brw_context *brw,
    if (!buf)
       return false;
 
+   enum isl_aux_state **aux_state =
+      create_aux_state_map(mt, ISL_AUX_STATE_PASS_THROUGH);
+   if (!aux_state) {
+      free(buf);
+      return false;
+   }
+
    buf->size = temp_ccs_surf.size;
    buf->pitch = temp_ccs_surf.row_pitch;
    buf->qpitch = isl_surf_get_array_pitch_sa_rows(&temp_ccs_surf);
@@ -1554,10 +1605,12 @@ intel_miptree_alloc_non_msrt_mcs(struct brw_context *brw,
                                 1, I915_TILING_Y, &buf->pitch, alloc_flags);
    if (!buf->bo) {
       free(buf);
+      free(aux_state);
       return false;
    }
 
    mt->mcs_buf = buf;
+   mt->aux_state = aux_state;
 
    /* From Gen9 onwards single-sampled (non-msrt) auxiliary buffers are
     * used for lossless compression which requires similar initialisation
@@ -1975,19 +2028,35 @@ intel_miptree_all_slices_resolve_depth(struct brw_context *brw,
                                           BLORP_HIZ_OP_DEPTH_RESOLVE);
 }
 
-enum intel_fast_clear_state
-intel_miptree_get_fast_clear_state(const struct intel_mipmap_tree *mt,
-                                   unsigned level, unsigned layer)
+bool
+intel_miptree_has_color_unresolved(const struct intel_mipmap_tree *mt,
+                                   unsigned start_level, unsigned num_levels,
+                                   unsigned start_layer, unsigned num_layers)
 {
-   intel_miptree_check_level_layer(mt, level, layer);
+   assert(_mesa_is_format_color_format(mt->format));
 
-   const struct intel_resolve_map *item =
-      intel_resolve_map_const_get(&mt->color_resolve_map, level, layer);
+   if (!mt->mcs_buf)
+      return false;
 
-   if (!item)
-      return INTEL_FAST_CLEAR_STATE_RESOLVED;
+   /* Clamp the level range to fit the miptree */
+   assert(start_level + num_levels >= start_level);
+   const uint32_t last_level =
+      MIN2(mt->last_level, start_level + num_levels - 1);
+   start_level = MAX2(mt->first_level, start_level);
+   num_levels = last_level - start_level + 1;
+
+   for (uint32_t level = start_level; level <= last_level; level++) {
+      const uint32_t level_layers = MIN2(num_layers, mt->level[level].depth);
+      for (unsigned a = 0; a < level_layers; a++) {
+         enum isl_aux_state aux_state =
+            intel_miptree_get_aux_state(mt, level, start_layer + a);
+         assert(aux_state != ISL_AUX_STATE_AUX_INVALID);
+         if (aux_state != ISL_AUX_STATE_PASS_THROUGH)
+            return true;
+      }
+   }
 
-   return item->fast_clear_state;
+   return false;
 }
 
 static void
@@ -2014,135 +2083,188 @@ intel_miptree_check_color_resolve(const struct brw_context *brw,
    (void)layer;
 }
 
-void
-intel_miptree_set_fast_clear_state(const struct brw_context *brw,
-                                   struct intel_mipmap_tree *mt,
-                                   unsigned level,
-                                   unsigned first_layer,
-                                   unsigned num_layers,
-                                   enum intel_fast_clear_state new_state)
+static enum blorp_fast_clear_op
+get_ccs_d_resolve_op(enum isl_aux_state aux_state,
+                     bool ccs_supported, bool fast_clear_supported)
 {
-   /* Setting the state to resolved means removing the item from the list
-    * altogether.
-    */
-   assert(new_state != INTEL_FAST_CLEAR_STATE_RESOLVED);
+   assert(ccs_supported == fast_clear_supported);
 
-   intel_miptree_check_color_resolve(brw, mt, level, first_layer);
+   switch (aux_state) {
+   case ISL_AUX_STATE_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      if (!ccs_supported)
+         return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
+      else
+         return BLORP_FAST_CLEAR_OP_NONE;
 
-   assert(first_layer + num_layers <= mt->physical_depth0);
+   case ISL_AUX_STATE_PASS_THROUGH:
+      return BLORP_FAST_CLEAR_OP_NONE;
 
-   for (unsigned i = 0; i < num_layers; i++)
-      intel_resolve_map_set(&mt->color_resolve_map, level,
-                            first_layer + i, new_state);
-}
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_AUX_INVALID:
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      break;
+   }
 
-bool
-intel_miptree_has_color_unresolved(const struct intel_mipmap_tree *mt,
-                                   unsigned start_level, unsigned num_levels,
-                                   unsigned start_layer, unsigned num_layers)
-{
-   return intel_resolve_map_find_any(&mt->color_resolve_map,
-                                     start_level, num_levels,
-                                     start_layer, num_layers) != NULL;
+   unreachable("Invalid aux state for CCS_D");
 }
 
-void
-intel_miptree_used_for_rendering(const struct brw_context *brw,
-                                 struct intel_mipmap_tree *mt, unsigned level,
-                                 unsigned start_layer, unsigned num_layers)
+static enum blorp_fast_clear_op
+get_ccs_e_resolve_op(enum isl_aux_state aux_state,
+                     bool ccs_supported, bool fast_clear_supported)
 {
-   const bool is_lossless_compressed =
-      intel_miptree_is_lossless_compressed(brw, mt);
+   switch (aux_state) {
+   case ISL_AUX_STATE_CLEAR:
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      if (!ccs_supported)
+         return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
+      else if (!fast_clear_supported)
+         return BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL;
+      else
+         return BLORP_FAST_CLEAR_OP_NONE;
 
-   for (unsigned i = 0; i < num_layers; ++i) {
-      const enum intel_fast_clear_state fast_clear_state =
-         intel_miptree_get_fast_clear_state(mt, level, start_layer + i);
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+      if (!ccs_supported)
+         return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
+      else
+         return BLORP_FAST_CLEAR_OP_NONE;
 
-      /* If the buffer was previously in fast clear state, change it to
-       * unresolved state, since it won't be guaranteed to be clear after
-       * rendering occurs.
-       */
-      if (is_lossless_compressed ||
-          fast_clear_state == INTEL_FAST_CLEAR_STATE_CLEAR) {
-         intel_miptree_set_fast_clear_state(
-            brw, mt, level, start_layer + i, 1,
-            INTEL_FAST_CLEAR_STATE_UNRESOLVED);
-      }
+   case ISL_AUX_STATE_PASS_THROUGH:
+      return BLORP_FAST_CLEAR_OP_NONE;
+
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_AUX_INVALID:
+      break;
    }
+
+   unreachable("Invalid aux state for CCS_E");
 }
 
-static bool
-intel_miptree_needs_color_resolve(const struct brw_context *brw,
-                                  const struct intel_mipmap_tree *mt,
-                                  int flags)
+static void
+intel_miptree_prepare_ccs_access(struct brw_context *brw,
+                                 struct intel_mipmap_tree *mt,
+                                 uint32_t level, uint32_t layer,
+                                 bool aux_supported,
+                                 bool fast_clear_supported)
 {
-   if (mt->aux_disable & INTEL_AUX_DISABLE_CCS)
-      return false;
+   enum isl_aux_state aux_state = intel_miptree_get_aux_state(mt, level, layer);
 
-   const bool is_lossless_compressed =
-      intel_miptree_is_lossless_compressed(brw, mt);
+   enum blorp_fast_clear_op resolve_op;
+   if (intel_miptree_is_lossless_compressed(brw, mt)) {
+      resolve_op = get_ccs_e_resolve_op(aux_state, aux_supported,
+                                        fast_clear_supported);
+   } else {
+      resolve_op = get_ccs_d_resolve_op(aux_state, aux_supported,
+                                        fast_clear_supported);
+   }
 
-   /* From gen9 onwards there is new compression scheme for single sampled
-    * surfaces called "lossless compressed". These don't need to be always
-    * resolved.
-    */
-   if ((flags & INTEL_MIPTREE_IGNORE_CCS_E) && is_lossless_compressed)
-      return false;
+   if (resolve_op != BLORP_FAST_CLEAR_OP_NONE) {
+      intel_miptree_check_color_resolve(brw, mt, level, layer);
+      brw_blorp_resolve_color(brw, mt, level, layer, resolve_op);
 
-   /* Fast color clear resolves only make sense for non-MSAA buffers. */
-   if (mt->msaa_layout != INTEL_MSAA_LAYOUT_NONE && !is_lossless_compressed)
-      return false;
+      switch (resolve_op) {
+      case BLORP_FAST_CLEAR_OP_RESOLVE_FULL:
+         /* 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.)
+          */
+         intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+                                     ISL_AUX_STATE_PASS_THROUGH);
+         break;
 
-   return true;
+      case BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL:
+         intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_NO_CLEAR);
+         break;
+
+      default:
+         unreachable("Invalid resolve op");
+      }
+   }
 }
 
-static bool
-intel_miptree_resolve_color(struct brw_context *brw,
-                            struct intel_mipmap_tree *mt,
-                            uint32_t start_level, uint32_t num_levels,
-                            uint32_t start_layer, uint32_t num_layers,
-                            int flags)
+static void
+intel_miptree_finish_ccs_write(struct brw_context *brw,
+                               struct intel_mipmap_tree *mt,
+                               uint32_t level, uint32_t layer,
+                               bool written_with_ccs)
 {
-   intel_miptree_check_color_resolve(brw, mt, start_level, start_layer);
+   enum isl_aux_state aux_state = intel_miptree_get_aux_state(mt, level, layer);
 
-   if (!intel_miptree_needs_color_resolve(brw, mt, flags))
-      return false;
+   if (intel_miptree_is_lossless_compressed(brw, mt)) {
+      switch (aux_state) {
+      case ISL_AUX_STATE_CLEAR:
+         assert(written_with_ccs);
+         intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_CLEAR);
+         break;
 
-   enum blorp_fast_clear_op resolve_op;
-   if (brw->gen >= 9) {
-      if (intel_miptree_is_lossless_compressed(brw, mt)) {
-         resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
-      } else {
-         resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL;
+      case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+         assert(written_with_ccs);
+         break; /* Nothing to do */
+
+      case ISL_AUX_STATE_PASS_THROUGH:
+         if (written_with_ccs) {
+            intel_miptree_set_aux_state(brw, mt, 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 {
-      /* Broadwell and earlier do not have a partial resolve */
-      assert(!intel_miptree_is_lossless_compressed(brw, mt));
-      resolve_op = BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
-   }
+      /* CCS_D is a bit simpler */
+      switch (aux_state) {
+      case ISL_AUX_STATE_CLEAR:
+         assert(written_with_ccs);
+         intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+                                     ISL_AUX_STATE_COMPRESSED_CLEAR);
+         break;
 
-   bool resolved = false;
-   foreach_list_typed_safe(struct intel_resolve_map, map, link,
-                           &mt->color_resolve_map) {
-      if (map->level < start_level ||
-          map->level >= (start_level + num_levels) ||
-          map->layer < start_layer ||
-          map->layer >= (start_layer + num_layers))
-         continue;
+      case ISL_AUX_STATE_COMPRESSED_CLEAR:
+         assert(written_with_ccs);
+         break; /* Nothing to do */
 
-      /* Arrayed and mip-mapped fast clear is only supported for gen8+. */
-      assert(brw->gen >= 8 || (map->level == 0 && map->layer == 0));
+      case ISL_AUX_STATE_PASS_THROUGH:
+         /* Nothing to do */
+         break;
+
+      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");
+      }
+   }
+}
 
-      intel_miptree_check_level_layer(mt, map->level, map->layer);
+static void
+intel_miptree_finish_mcs_write(struct brw_context *brw,
+                               struct intel_mipmap_tree *mt,
+                               uint32_t level, uint32_t layer,
+                               bool written_with_aux)
+{
+   switch (intel_miptree_get_aux_state(mt, level, layer)) {
+   case ISL_AUX_STATE_CLEAR:
+      assert(written_with_aux);
+      intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+                                  ISL_AUX_STATE_COMPRESSED_CLEAR);
+      break;
 
-      assert(map->fast_clear_state != INTEL_FAST_CLEAR_STATE_RESOLVED);
+   case ISL_AUX_STATE_COMPRESSED_CLEAR:
+      assert(written_with_aux);
+      break; /* Nothing to do */
 
-      brw_blorp_resolve_color(brw, mt, map->level, map->layer, resolve_op);
-      intel_resolve_map_remove(map);
-      resolved = true;
+   case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
+   case ISL_AUX_STATE_RESOLVED:
+   case ISL_AUX_STATE_PASS_THROUGH:
+   case ISL_AUX_STATE_AUX_INVALID:
+      unreachable("Invalid aux state for MCS");
    }
-
-   return resolved;
 }
 
 static inline uint32_t
@@ -2193,11 +2315,17 @@ intel_miptree_prepare_access(struct brw_context *brw,
 
       if (mt->num_samples > 1) {
          /* Nothing to do for MSAA */
+         assert(aux_supported && fast_clear_supported);
       } else {
-         /* TODO: This is fairly terrible.  We can do better. */
-         if (!aux_supported || !fast_clear_supported) {
-            intel_miptree_resolve_color(brw, mt, start_level, num_levels,
-                                        start_layer, num_layers, 0);
+         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(mt, level, start_layer, num_layers);
+            for (uint32_t a = 0; a < level_layers; a++) {
+               intel_miptree_prepare_ccs_access(brw, mt, level,
+                                                start_layer + a, aux_supported,
+                                                fast_clear_supported);
+            }
          }
       }
    } else if (mt->format == MESA_FORMAT_S_UINT8) {
@@ -2229,12 +2357,18 @@ intel_miptree_finish_write(struct brw_context *brw,
    num_layers = miptree_layer_range_length(mt, level, start_layer, num_layers);
 
    if (_mesa_is_format_color_format(mt->format)) {
+      if (!mt->mcs_buf)
+         return;
+
       if (mt->num_samples > 1) {
-         /* Nothing to do for MSAA */
+         for (uint32_t a = 0; a < num_layers; a++) {
+            intel_miptree_finish_mcs_write(brw, mt, level, start_layer + a,
+                                           written_with_aux);
+         }
       } else {
-         if (written_with_aux) {
-            intel_miptree_used_for_rendering(brw, mt, level,
-                                             start_layer, num_layers);
+         for (uint32_t a = 0; a < num_layers; a++) {
+            intel_miptree_finish_ccs_write(brw, mt, level, start_layer + a,
+                                           written_with_aux);
          }
       }
    } else if (mt->format == MESA_FORMAT_S_UINT8) {
@@ -2263,22 +2397,12 @@ enum isl_aux_state
 intel_miptree_get_aux_state(const struct intel_mipmap_tree *mt,
                             uint32_t level, uint32_t layer)
 {
+   intel_miptree_check_level_layer(mt, level, layer);
+
    if (_mesa_is_format_color_format(mt->format)) {
       assert(mt->mcs_buf != NULL);
-      if (mt->num_samples > 1) {
-         return ISL_AUX_STATE_COMPRESSED_CLEAR;
-      } else {
-         switch (intel_miptree_get_fast_clear_state(mt, level, layer)) {
-         case INTEL_FAST_CLEAR_STATE_RESOLVED:
-            return ISL_AUX_STATE_RESOLVED;
-         case INTEL_FAST_CLEAR_STATE_UNRESOLVED:
-            return ISL_AUX_STATE_COMPRESSED_CLEAR;
-         case INTEL_FAST_CLEAR_STATE_CLEAR:
-            return ISL_AUX_STATE_CLEAR;
-         default:
-            unreachable("Invalid fast clear state");
-         }
-      }
+      assert(mt->num_samples <= 1 || mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS);
+      return mt->aux_state[level][layer];
    } else if (mt->format == MESA_FORMAT_S_UINT8) {
       unreachable("Cannot get aux state for stencil");
    } else {
@@ -2306,19 +2430,20 @@ intel_miptree_set_aux_state(struct brw_context *brw,
 {
    num_layers = miptree_layer_range_length(mt, level, start_layer, num_layers);
 
-   /* Right now, this only applies to clears. */
-   assert(aux_state == ISL_AUX_STATE_CLEAR);
-
    if (_mesa_is_format_color_format(mt->format)) {
-      if (mt->num_samples > 1)
-         assert(mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS);
+      assert(mt->mcs_buf != NULL);
+      assert(mt->num_samples <= 1 || mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS);
 
-      assert(level == 0 && start_layer == 0 && num_layers == 1);
-      intel_miptree_set_fast_clear_state(brw, mt, 0, 0, 1,
-                                         INTEL_FAST_CLEAR_STATE_CLEAR);
+      for (unsigned a = 0; a < num_layers; a++)
+         mt->aux_state[level][start_layer + a] = aux_state;
    } else if (mt->format == MESA_FORMAT_S_UINT8) {
-      assert(!"Cannot set aux state for stencil");
+      unreachable("Cannot get aux state for stencil");
    } else {
+      assert(mt->hiz_buf != NULL);
+
+      /* Right now, this only applies to clears. */
+      assert(aux_state == ISL_AUX_STATE_CLEAR);
+
       for (unsigned a = 0; a < num_layers; a++) {
          intel_miptree_check_level_layer(mt, level, start_layer);
          intel_resolve_map_set(&mt->hiz_map, level, start_layer + a,
@@ -2339,22 +2464,23 @@ intel_miptree_set_aux_state(struct brw_context *brw,
  * set).
  */
 static bool
-intel_texture_view_requires_resolve(struct brw_context *brw,
-                                    struct intel_mipmap_tree *mt,
-                                    mesa_format format)
+can_texture_with_ccs(struct brw_context *brw,
+                     struct intel_mipmap_tree *mt,
+                     mesa_format view_format)
 {
-   if (brw->gen < 9 ||
-       !intel_miptree_is_lossless_compressed(brw, mt))
-     return false;
+   if (!intel_miptree_is_lossless_compressed(brw, mt))
+      return false;
 
-   const enum isl_format isl_format = brw_isl_format_for_mesa_format(format);
+   enum isl_format isl_mt_format = brw_isl_format_for_mesa_format(mt->format);
+   enum isl_format isl_view_format = brw_isl_format_for_mesa_format(view_format);
 
-   if (isl_format_supports_ccs_e(&brw->screen->devinfo, isl_format))
+   if (!isl_formats_are_ccs_e_compatible(&brw->screen->devinfo,
+                                         isl_mt_format, isl_view_format)) {
+      perf_debug("Incompatible sampling format (%s) for rbc (%s)\n",
+                 _mesa_get_format_name(view_format),
+                 _mesa_get_format_name(mt->format));
       return false;
-
-   perf_debug("Incompatible sampling format (%s) for rbc (%s)\n",
-              _mesa_get_format_name(format),
-              _mesa_get_format_name(mt->format));
+   }
 
    return true;
 }
@@ -2367,19 +2493,29 @@ intel_miptree_prepare_texture_slices(struct brw_context *brw,
                                      uint32_t start_layer, uint32_t num_layers,
                                      bool *aux_supported_out)
 {
-   bool aux_supported;
+   bool aux_supported, clear_supported;
    if (_mesa_is_format_color_format(mt->format)) {
-      aux_supported = intel_miptree_is_lossless_compressed(brw, mt) &&
-                      !intel_texture_view_requires_resolve(brw, mt, view_format);
+      if (mt->num_samples > 1) {
+         aux_supported = clear_supported = true;
+      } else {
+         aux_supported = can_texture_with_ccs(brw, mt, view_format);
+
+         /* 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.
+          */
+         clear_supported = aux_supported && (mt->format == view_format);
+      }
    } else if (mt->format == MESA_FORMAT_S_UINT8) {
-      aux_supported = false;
+      aux_supported = clear_supported = false;
    } else {
-      aux_supported = intel_miptree_sample_with_hiz(brw, mt);
+      aux_supported = clear_supported = intel_miptree_sample_with_hiz(brw, mt);
    }
 
    intel_miptree_prepare_access(brw, mt, start_level, num_levels,
                                 start_layer, num_layers,
-                                aux_supported, aux_supported);
+                                aux_supported, clear_supported);
    if (aux_supported_out)
       *aux_supported_out = aux_supported;
 }
@@ -2517,7 +2653,8 @@ intel_miptree_make_shareable(struct brw_context *brw,
        * execute any will likely crash due to the missing aux buffer. So let's
        * delete all pending ops.
        */
-      exec_list_make_empty(&mt->color_resolve_map);
+      free(mt->aux_state);
+      mt->aux_state = NULL;
    }
 
    if (mt->hiz_buf) {
index 5004ace95b31f9ac5b90dd0784a3cba1e40d52dc..97f5c286f1b94507783a3c0bae4475ed9d2faf5b 100644 (file)
@@ -592,7 +592,14 @@ struct intel_mipmap_tree
     * indicates state other than RESOLVED.
     */
    struct exec_list hiz_map; /* List of intel_resolve_map. */
-   struct exec_list color_resolve_map; /* List of intel_resolve_map. */
+
+   /**
+    * \brief Maps miptree slices to their current aux state
+    *
+    * This two-dimensional array is indexed as [level][layer] and stores an
+    * aux state for each slice.
+    */
+   enum isl_aux_state **aux_state;
 
    /**
     * \brief Stencil miptree for depthstencil textures.
@@ -862,41 +869,11 @@ intel_miptree_all_slices_resolve_depth(struct brw_context *brw,
 
 /**\}*/
 
-enum intel_fast_clear_state
-intel_miptree_get_fast_clear_state(const struct intel_mipmap_tree *mt,
-                                   unsigned level, unsigned layer);
-
-void
-intel_miptree_set_fast_clear_state(const struct brw_context *brw,
-                                   struct intel_mipmap_tree *mt,
-                                   unsigned level,
-                                   unsigned first_layer,
-                                   unsigned num_layers,
-                                   enum intel_fast_clear_state new_state);
-
 bool
 intel_miptree_has_color_unresolved(const struct intel_mipmap_tree *mt,
                                    unsigned start_level, unsigned num_levels,
                                    unsigned start_layer, unsigned num_layers);
 
-/**
- * Update the fast clear state for a miptree to indicate that it has been used
- * for rendering.
- */
-void
-intel_miptree_used_for_rendering(const struct brw_context *brw,
-                                 struct intel_mipmap_tree *mt, unsigned level,
-                                 unsigned start_layer, unsigned num_layers);
-
-/**
- * Flag values telling color resolve pass which special types of buffers
- * can be ignored.
- *
- * INTEL_MIPTREE_IGNORE_CCS_E:   Lossless compressed (single-sample
- *                               compression scheme since gen9)
- */
-#define INTEL_MIPTREE_IGNORE_CCS_E (1 << 0)
-
 
 #define INTEL_REMAINING_LAYERS UINT32_MAX
 #define INTEL_REMAINING_LEVELS UINT32_MAX
index 17d3983f5e55adbbede4707710aee4f6bbeb9906..771d855b0014f627c9ef25941142fa5d84e794f2 100644 (file)
 extern "C" {
 #endif
 
-/**
- * Enum for keeping track of the fast clear state of a buffer associated with
- * a miptree.
- *
- * Fast clear works by deferring the memory writes that would be used to clear
- * the buffer, so that instead of performing them at the time of the clear
- * operation, the hardware automatically performs them at the time that the
- * buffer is later accessed for rendering.  The MCS buffer keeps track of
- * which regions of the buffer still have pending clear writes.
- *
- * This enum keeps track of the driver's knowledge of pending fast clears in
- * the MCS buffer.
- *
- * MCS buffers only exist on Gen7+.
- */
-enum intel_fast_clear_state
-{
-   /**
-    * No deferred clears are pending for this miptree, and the contents of the
-    * color buffer are entirely correct.  An MCS buffer may or may not exist
-    * for this miptree.  If it does exist, it is entirely in the "no deferred
-    * clears pending" state.  If it does not exist, it will be created the
-    * first time a fast color clear is executed.
-    *
-    * In this state, the color buffer can be used for purposes other than
-    * rendering without needing a render target resolve.
-    *
-    * Since there is no such thing as a "fast color clear resolve" for MSAA
-    * buffers, an MSAA buffer will never be in this state.
-    */
-   INTEL_FAST_CLEAR_STATE_RESOLVED,
-
-   /**
-    * An MCS buffer exists for this miptree, and deferred clears are pending
-    * for some regions of the color buffer, as indicated by the MCS buffer.
-    * The contents of the color buffer are only correct for the regions where
-    * the MCS buffer doesn't indicate a deferred clear.
-    *
-    * If a single-sample buffer is in this state, a render target resolve must
-    * be performed before it can be used for purposes other than rendering.
-    */
-   INTEL_FAST_CLEAR_STATE_UNRESOLVED,
-
-   /**
-    * An MCS buffer exists for this miptree, and deferred clears are pending
-    * for the entire color buffer, and the contents of the MCS buffer reflect
-    * this.  The contents of the color buffer are undefined.
-    *
-    * If a single-sample buffer is in this state, a render target resolve must
-    * be performed before it can be used for purposes other than rendering.
-    *
-    * If the client attempts to clear a buffer which is already in this state,
-    * the clear can be safely skipped, since the buffer is already clear.
-    */
-   INTEL_FAST_CLEAR_STATE_CLEAR,
-};
-
 /**
  * \brief Map of miptree slices to needed resolves.
  *
@@ -121,10 +64,7 @@ struct intel_resolve_map {
    uint32_t level;
    uint32_t layer;
 
-   union {
-      enum blorp_hiz_op need;
-      enum intel_fast_clear_state fast_clear_state;
-   };
+   enum blorp_hiz_op need;
 };
 
 void