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);
}
}
+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,
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]);
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,
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);
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
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
(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
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) {
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) {
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 {
{
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,
* 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;
}
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;
}
* 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) {