From: Jason Ekstrand Date: Thu, 25 May 2017 05:09:30 +0000 (-0700) Subject: i965/miptree: Add new entrypoints for resolve management X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5ec344e42056c14417ec423be61e3715fae7b626;p=mesa.git i965/miptree: Add new entrypoints for resolve management This commit adds a new unified interface for doing resolves. The basic format is that, prior to any surface access such as texturing or rendering, you call intel_miptree_prepare_access. If the surface was written, you call intel_miptree_finish_write. These two functions take parameters which tell them whether or not auxiliary compression and fast clears are supported on the surface. Later commits will add wrappers around these two functions for texturing, rendering, etc. Reviewed-by: Topi Pohjolainen --- diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c index 42df708b316..04ac46f789c 100644 --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c @@ -2220,6 +2220,185 @@ intel_miptree_all_slices_resolve_color(struct brw_context *brw, intel_miptree_resolve_color(brw, mt, 0, UINT32_MAX, 0, UINT32_MAX, flags); } +static inline uint32_t +miptree_level_range_length(const struct intel_mipmap_tree *mt, + uint32_t start_level, uint32_t num_levels) +{ + assert(start_level >= mt->first_level); + assert(start_level <= mt->last_level); + + if (num_levels == INTEL_REMAINING_LAYERS) + num_levels = mt->last_level - start_level + 1; + /* Check for overflow */ + assert(start_level + num_levels >= start_level); + assert(start_level + num_levels <= mt->last_level + 1); + + return num_levels; +} + +static inline uint32_t +miptree_layer_range_length(const struct intel_mipmap_tree *mt, uint32_t level, + uint32_t start_layer, uint32_t num_layers) +{ + assert(level <= mt->last_level); + uint32_t total_num_layers = mt->level[level].depth; + + 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; +} + +void +intel_miptree_prepare_access(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, + bool aux_supported, bool fast_clear_supported) +{ + num_levels = miptree_level_range_length(mt, start_level, num_levels); + + if (_mesa_is_format_color_format(mt->format)) { + if (!mt->mcs_buf) + return; + + if (mt->num_samples > 1) { + /* Nothing to do for MSAA */ + } 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); + } + } + } else if (mt->format == MESA_FORMAT_S_UINT8) { + /* Nothing to do for stencil */ + } else { + if (!mt->hiz_buf) + return; + + if (aux_supported) { + assert(fast_clear_supported); + intel_miptree_depth_hiz_resolve(brw, mt, start_level, num_levels, + start_layer, num_layers, + BLORP_HIZ_OP_HIZ_RESOLVE); + } else { + assert(!fast_clear_supported); + intel_miptree_depth_hiz_resolve(brw, mt, start_level, num_levels, + start_layer, num_layers, + BLORP_HIZ_OP_DEPTH_RESOLVE); + } + } +} + +void +intel_miptree_finish_write(struct brw_context *brw, + struct intel_mipmap_tree *mt, uint32_t level, + uint32_t start_layer, uint32_t num_layers, + bool written_with_aux) +{ + num_layers = miptree_layer_range_length(mt, level, start_layer, num_layers); + + if (_mesa_is_format_color_format(mt->format)) { + if (mt->num_samples > 1) { + /* Nothing to do for MSAA */ + } else { + if (written_with_aux) { + intel_miptree_used_for_rendering(brw, mt, level, + start_layer, num_layers); + } + } + } else if (mt->format == MESA_FORMAT_S_UINT8) { + /* Nothing to do for stencil */ + } else { + if (written_with_aux) { + for (unsigned a = 0; a < num_layers; a++) { + intel_miptree_check_level_layer(mt, level, start_layer); + intel_miptree_slice_set_needs_depth_resolve(mt, level, + start_layer + a); + } + } else { + for (unsigned a = 0; a < num_layers; a++) { + intel_miptree_check_level_layer(mt, level, start_layer); + intel_miptree_slice_set_needs_hiz_resolve(mt, level, + start_layer + a); + } + } + } +} + +enum isl_aux_state +intel_miptree_get_aux_state(const struct intel_mipmap_tree *mt, + uint32_t level, uint32_t 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"); + } + } + } else if (mt->format == MESA_FORMAT_S_UINT8) { + unreachable("Cannot get aux state for stencil"); + } else { + assert(mt->hiz_buf != NULL); + const struct intel_resolve_map *map = + intel_resolve_map_const_get(&mt->hiz_map, level, layer); + if (!map) + return ISL_AUX_STATE_RESOLVED; + switch (map->need) { + case BLORP_HIZ_OP_DEPTH_RESOLVE: + return ISL_AUX_STATE_COMPRESSED_CLEAR; + case BLORP_HIZ_OP_HIZ_RESOLVE: + return ISL_AUX_STATE_AUX_INVALID; + default: + unreachable("Invalid hiz op"); + } + } +} + +void +intel_miptree_set_aux_state(struct brw_context *brw, + struct intel_mipmap_tree *mt, uint32_t level, + uint32_t start_layer, uint32_t num_layers, + enum isl_aux_state aux_state) +{ + 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(level == 0 && start_layer == 0 && num_layers == 1); + intel_miptree_set_fast_clear_state(brw, mt, 0, 0, 1, + INTEL_FAST_CLEAR_STATE_CLEAR); + } else if (mt->format == MESA_FORMAT_S_UINT8) { + assert(!"Cannot set aux state for stencil"); + } else { + for (unsigned a = 0; a < num_layers; a++) { + intel_miptree_check_level_layer(mt, level, start_layer); + intel_miptree_slice_set_needs_depth_resolve(mt, level, + start_layer + a); + } + } +} + /** * Make it possible to share the BO backing the given miptree with another * process or another miptree. diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h index ac928e8f3be..77572292f63 100644 --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h @@ -947,6 +947,86 @@ intel_miptree_all_slices_resolve_color(struct brw_context *brw, struct intel_mipmap_tree *mt, int flags); +#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 +intel_miptree_prepare_access(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, + bool aux_supported, 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 + * intel_miptree_prepare_access and intel_miptree_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 +intel_miptree_finish_write(struct brw_context *brw, + struct intel_mipmap_tree *mt, uint32_t level, + uint32_t start_layer, uint32_t num_layers, + bool written_with_aux); + +/** Get the auxiliary compression state of a miptree slice */ +enum isl_aux_state +intel_miptree_get_aux_state(const struct intel_mipmap_tree *mt, + 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 intel_miptree_prepare_access or intel_miptree_finish_write. + */ +void +intel_miptree_set_aux_state(struct brw_context *brw, + struct intel_mipmap_tree *mt, uint32_t level, + uint32_t start_layer, uint32_t num_layers, + enum isl_aux_state aux_state); + void intel_miptree_make_shareable(struct brw_context *brw, struct intel_mipmap_tree *mt);