#include <GL/gl.h>
#include <GL/internal/dri_interface.h>
+#include <drm_fourcc.h>
#include "intel_batchbuffer.h"
#include "intel_image.h"
struct intel_mipmap_tree *mt);
static bool
-is_mcs_supported(const struct brw_context *brw, mesa_format format,
- uint32_t layout_flags)
+intel_miptree_supports_mcs(struct brw_context *brw,
+ const struct intel_mipmap_tree *mt)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
+ /* MCS compression only applies to multisampled miptrees */
+ if (mt->surf.samples <= 1)
+ return false;
+
/* Prior to Gen7, all MSAA surfaces used IMS layout. */
- if (brw->gen < 7)
+ if (devinfo->gen < 7)
return false;
/* In Gen7, IMS layout is only used for depth and stencil buffers. */
- switch (_mesa_get_format_base_format(format)) {
+ switch (_mesa_get_format_base_format(mt->format)) {
case GL_DEPTH_COMPONENT:
case GL_STENCIL_INDEX:
case GL_DEPTH_STENCIL:
* would require converting between CMS and UMS MSAA layouts on the fly,
* which is expensive.
*/
- if (brw->gen == 7 && _mesa_get_format_datatype(format) == GL_INT) {
- return false;
- } else if (layout_flags & MIPTREE_LAYOUT_DISABLE_AUX) {
- /* We can't use the CMS layout because it uses an aux buffer, the MCS
- * buffer. So fallback to UMS, which is identical to CMS without the
- * MCS. */
+ if (devinfo->gen == 7 && _mesa_get_format_datatype(mt->format) == GL_INT) {
return false;
} else {
return true;
intel_tiling_supports_ccs(const struct brw_context *brw,
enum isl_tiling tiling)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
/* From the Ivy Bridge PRM, Vol2 Part1 11.7 "MCS Buffer for Render
* Target(s)", beneath the "Fast Color Clear" bullet (p326):
*
*
* Gen9 changes the restriction to Y-tile only.
*/
- if (brw->gen >= 9)
+ if (devinfo->gen >= 9)
return tiling == ISL_TILING_Y0;
- else if (brw->gen >= 7)
+ else if (devinfo->gen >= 7)
return tiling != ISL_TILING_LINEAR;
else
return false;
intel_miptree_supports_ccs(struct brw_context *brw,
const struct intel_mipmap_tree *mt)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
/* MCS support does not exist prior to Gen7 */
- if (brw->gen < 7)
+ if (devinfo->gen < 7)
return false;
/* This function applies only to non-multisampled render targets. */
* surfaces are supported with MCS buffer layout with these alignments in
* the RT space: Horizontal Alignment = 128 and Vertical Alignment = 64.
*/
- if (brw->gen < 8 && (mip_mapped || arrayed))
+ if (devinfo->gen < 8 && (mip_mapped || arrayed))
return false;
/* There's no point in using an MCS buffer if the surface isn't in a
if (!brw->mesa_format_supports_render[mt->format])
return false;
- if (brw->gen >= 9) {
- mesa_format linear_format = _mesa_get_srgb_format_linear(mt->format);
- const enum isl_format isl_format =
- brw_isl_format_for_mesa_format(linear_format);
- return isl_format_supports_ccs_e(&brw->screen->devinfo, isl_format);
- } else
- return true;
+ return true;
}
static bool
intel_tiling_supports_hiz(const struct brw_context *brw,
enum isl_tiling tiling)
{
- if (brw->gen < 6)
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
+ if (devinfo->gen < 6)
return false;
return tiling == ISL_TILING_Y0;
intel_miptree_supports_ccs_e(struct brw_context *brw,
const struct intel_mipmap_tree *mt)
{
- if (brw->gen < 9)
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
+ if (devinfo->gen < 9)
return false;
/* For now compression is only enabled for integer formats even though
if (!intel_miptree_supports_ccs(brw, mt))
return false;
- /* Fast clear can be also used to clear srgb surfaces by using equivalent
- * linear format. This trick, however, can't be extended to be used with
- * lossless compression and therefore a check is needed to see if the format
- * really is linear.
+ /* Many window system buffers are sRGB even if they are never rendered as
+ * sRGB. For those, we want CCS_E for when sRGBEncode is false. When the
+ * surface is used as sRGB, we fall back to CCS_D.
*/
- return _mesa_get_srgb_format_linear(mt->format) == mt->format;
+ mesa_format linear_format = _mesa_get_srgb_format_linear(mt->format);
+ enum isl_format isl_format = brw_isl_format_for_mesa_format(linear_format);
+ return isl_format_supports_ccs_e(&brw->screen->devinfo, isl_format);
}
/**
static bool
needs_separate_stencil(const struct brw_context *brw,
struct intel_mipmap_tree *mt,
- mesa_format format, uint32_t layout_flags)
+ mesa_format format)
{
-
- if (layout_flags & MIPTREE_LAYOUT_FOR_BO)
- return false;
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
if (_mesa_get_format_base_format(format) != GL_DEPTH_STENCIL)
return false;
- if (brw->must_use_separate_stencil)
+ if (devinfo->must_use_separate_stencil)
return true;
return brw->has_separate_stencil &&
{
assert(mt->aux_usage == ISL_AUX_USAGE_NONE);
- const unsigned no_flags = 0;
- if (mt->surf.samples > 1 && is_mcs_supported(brw, mt->format, no_flags)) {
+ if (intel_miptree_supports_mcs(brw, mt)) {
assert(mt->surf.msaa_layout == ISL_MSAA_LAYOUT_ARRAY);
mt->aux_usage = ISL_AUX_USAGE_MCS;
} else if (intel_tiling_supports_ccs(brw, mt->surf.tiling) &&
mesa_format
intel_lower_compressed_format(struct brw_context *brw, mesa_format format)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
/* No need to lower ETC formats on these platforms,
* they are supported natively.
*/
- if (brw->gen >= 8 || brw->is_baytrail)
+ if (devinfo->gen >= 8 || devinfo->is_baytrail)
return format;
switch (format) {
}
}
-static unsigned
-get_num_logical_layers(const struct intel_mipmap_tree *mt, unsigned level)
+unsigned
+brw_get_num_logical_layers(const struct intel_mipmap_tree *mt, unsigned level)
{
if (mt->surf.dim == ISL_SURF_DIM_3D)
return minify(mt->surf.logical_level0_px.depth, level);
return mt->surf.logical_level0_px.array_len;
}
-static unsigned
+UNUSED static unsigned
get_num_phys_layers(const struct isl_surf *surf, unsigned level)
{
/* In case of physical dimensions one needs to consider also the layout.
uint32_t total_slices = 0;
for (uint32_t level = 0; level < levels; level++)
- total_slices += get_num_logical_layers(mt, level);
+ total_slices += brw_get_num_logical_layers(mt, level);
const size_t per_level_array_size = levels * sizeof(enum isl_aux_state *);
enum isl_aux_state *s = data + per_level_array_size;
for (uint32_t level = 0; level < levels; level++) {
per_level_arr[level] = s;
- const unsigned level_layers = get_num_logical_layers(mt, level);
+ const unsigned level_layers = brw_get_num_logical_layers(mt, level);
for (uint32_t a = 0; a < level_layers; a++)
*(s++) = initial;
}
need_to_retile_as_x(const struct brw_context *brw, uint64_t size,
enum isl_tiling tiling)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
/* If the BO is too large to fit in the aperture, we need to use the
* BLT engine to support it. Prior to Sandybridge, the BLT paths can't
* handle Y-tiling, so we need to fall back to X.
*/
- if (brw->gen < 6 && size >= brw->max_gtt_map_object_size &&
+ if (devinfo->gen < 6 && size >= brw->max_gtt_map_object_size &&
tiling == ISL_TILING_Y0)
return true;
.array_len = target == GL_TEXTURE_3D ? 1 : depth0,
.samples = num_samples,
.row_pitch = row_pitch,
- .usage = isl_usage_flags,
+ .usage = isl_usage_flags,
.tiling_flags = tiling_flags,
};
if (!isl_surf_init_s(&brw->isl_dev, &mt->surf, &init_info))
goto fail;
- /* In case caller doesn't specifically request Y-tiling (needed
- * unconditionally for depth), check for corner cases needing special
- * treatment.
+ /* Depth surfaces are always Y-tiled and stencil is always W-tiled, although
+ * on gen7 platforms we also need to create Y-tiled copies of stencil for
+ * texturing since the hardware can't sample from W-tiled surfaces. For
+ * everything else, check for corner cases needing special treatment.
*/
- if (tiling_flags & ~ISL_TILING_Y0_BIT) {
+ bool is_depth_stencil =
+ mt->surf.usage & (ISL_SURF_USAGE_STENCIL_BIT | ISL_SURF_USAGE_DEPTH_BIT);
+ if (!is_depth_stencil) {
if (need_to_retile_as_linear(brw, mt->surf.row_pitch,
mt->surf.tiling, mt->surf.samples)) {
init_info.tiling_flags = 1u << ISL_TILING_LINEAR;
mt->aux_state = NULL;
mt->cpp = isl_format_get_layout(mt->surf.format)->bpb / 8;
mt->compressed = _mesa_is_format_compressed(format);
+ mt->drm_modifier = DRM_FORMAT_MOD_INVALID;
return mt;
mt->surf.samples, ISL_TILING_W_BIT,
ISL_SURF_USAGE_STENCIL_BIT |
ISL_SURF_USAGE_TEXTURE_BIT,
- BO_ALLOC_FOR_RENDER, 0, NULL);
+ BO_ALLOC_BUSY, 0, NULL);
if (!mt->stencil_mt)
return false;
-
+
mt->stencil_mt->r8stencil_needs_update = true;
return true;
}
-static bool
-force_linear_tiling(uint32_t layout_flags)
-{
- /* ANY includes NONE and Y bit. */
- if (layout_flags & MIPTREE_LAYOUT_TILING_Y)
- return false;
-
- return layout_flags & MIPTREE_LAYOUT_TILING_NONE;
-}
-
static struct intel_mipmap_tree *
miptree_create(struct brw_context *brw,
GLenum target,
GLuint height0,
GLuint depth0,
GLuint num_samples,
- uint32_t layout_flags)
+ enum intel_miptree_create_flags flags)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
if (format == MESA_FORMAT_S_UINT8)
return make_surface(brw, target, format, first_level, last_level,
width0, height0, depth0, num_samples,
ISL_TILING_W_BIT,
ISL_SURF_USAGE_STENCIL_BIT |
ISL_SURF_USAGE_TEXTURE_BIT,
- BO_ALLOC_FOR_RENDER,
+ BO_ALLOC_BUSY,
0,
NULL);
const GLenum base_format = _mesa_get_format_base_format(format);
if ((base_format == GL_DEPTH_COMPONENT ||
base_format == GL_DEPTH_STENCIL) &&
- !force_linear_tiling(layout_flags)) {
+ !(flags & MIPTREE_CREATE_LINEAR)) {
/* Fix up the Z miptree format for how we're splitting out separate
* stencil. Gen7 expects there to be no stencil bits in its depth buffer.
*/
const mesa_format depth_only_format =
intel_depth_format_for_depthstencil_format(format);
struct intel_mipmap_tree *mt = make_surface(
- brw, target, brw->gen >= 6 ? depth_only_format : format,
+ brw, target, devinfo->gen >= 6 ? depth_only_format : format,
first_level, last_level,
width0, height0, depth0, num_samples, ISL_TILING_Y0_BIT,
ISL_SURF_USAGE_DEPTH_BIT | ISL_SURF_USAGE_TEXTURE_BIT,
- BO_ALLOC_FOR_RENDER, 0, NULL);
+ BO_ALLOC_BUSY, 0, NULL);
- if (needs_separate_stencil(brw, mt, format, layout_flags) &&
+ if (needs_separate_stencil(brw, mt, format) &&
!make_separate_stencil_surface(brw, mt)) {
intel_miptree_release(&mt);
return NULL;
}
- if (!(layout_flags & MIPTREE_LAYOUT_DISABLE_AUX))
+ if (!(flags & MIPTREE_CREATE_NO_AUX))
intel_miptree_choose_aux_usage(brw, mt);
return mt;
etc_format = (format != tex_format) ? tex_format : MESA_FORMAT_NONE;
- assert((layout_flags & MIPTREE_LAYOUT_FOR_BO) == 0);
- if (layout_flags & MIPTREE_LAYOUT_ACCELERATED_UPLOAD)
- alloc_flags |= BO_ALLOC_FOR_RENDER;
+ if (flags & MIPTREE_CREATE_BUSY)
+ alloc_flags |= BO_ALLOC_BUSY;
- isl_tiling_flags_t tiling_flags = force_linear_tiling(layout_flags) ?
+ isl_tiling_flags_t tiling_flags = (flags & MIPTREE_CREATE_LINEAR) ?
ISL_TILING_LINEAR_BIT : ISL_TILING_ANY_MASK;
/* TODO: This used to be because there wasn't BLORP to handle Y-tiling. */
- if (brw->gen < 6)
+ if (devinfo->gen < 6)
tiling_flags &= ~ISL_TILING_Y0_BIT;
struct intel_mipmap_tree *mt = make_surface(
mt->etc_format = etc_format;
- if (layout_flags & MIPTREE_LAYOUT_FOR_SCANOUT)
- mt->bo->cache_coherent = false;
-
- if (!(layout_flags & MIPTREE_LAYOUT_DISABLE_AUX))
+ if (!(flags & MIPTREE_CREATE_NO_AUX))
intel_miptree_choose_aux_usage(brw, mt);
return mt;
GLuint height0,
GLuint depth0,
GLuint num_samples,
- uint32_t layout_flags)
+ enum intel_miptree_create_flags flags)
{
assert(num_samples > 0);
brw, target, format,
first_level, last_level,
width0, height0, depth0, num_samples,
- layout_flags);
+ flags);
if (!mt)
return NULL;
uint32_t height,
uint32_t depth,
int pitch,
- uint32_t layout_flags)
+ enum intel_miptree_create_flags flags)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
struct intel_mipmap_tree *mt;
uint32_t tiling, swizzle;
const GLenum target = depth > 1 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
const mesa_format depth_only_format =
intel_depth_format_for_depthstencil_format(format);
mt = make_surface(brw, target,
- brw->gen >= 6 ? depth_only_format : format,
+ devinfo->gen >= 6 ? depth_only_format : format,
0, 0, width, height, depth, 1, ISL_TILING_Y0_BIT,
ISL_SURF_USAGE_DEPTH_BIT | ISL_SURF_USAGE_TEXTURE_BIT,
- BO_ALLOC_FOR_RENDER, pitch, bo);
+ BO_ALLOC_BUSY, pitch, bo);
+ if (!mt)
+ return NULL;
brw_bo_reference(bo);
- if (!(layout_flags & MIPTREE_LAYOUT_DISABLE_AUX))
+ if (!(flags & MIPTREE_CREATE_NO_AUX))
intel_miptree_choose_aux_usage(brw, mt);
return mt;
ISL_TILING_W_BIT,
ISL_SURF_USAGE_STENCIL_BIT |
ISL_SURF_USAGE_TEXTURE_BIT,
- BO_ALLOC_FOR_RENDER, pitch, bo);
+ BO_ALLOC_BUSY, pitch, bo);
if (!mt)
return NULL;
/* The BO already has a tiling format and we shouldn't confuse the lower
* layers by making it try to find a tiling format again.
*/
- assert((layout_flags & MIPTREE_LAYOUT_TILING_ANY) == 0);
- assert((layout_flags & MIPTREE_LAYOUT_TILING_NONE) == 0);
+ assert((flags & MIPTREE_CREATE_LINEAR) == 0);
mt = make_surface(brw, target, format,
0, 0, width, height, depth, 1,
mt->bo = bo;
mt->offset = offset;
- if (!(layout_flags & MIPTREE_LAYOUT_DISABLE_AUX))
+ if (!(flags & MIPTREE_CREATE_NO_AUX)) {
intel_miptree_choose_aux_usage(brw, mt);
+ if (!intel_miptree_alloc_aux(brw, mt)) {
+ intel_miptree_release(&mt);
+ return NULL;
+ }
+ }
+
return mt;
}
miptree_create_for_planar_image(struct brw_context *brw,
__DRIimage *image, GLenum target)
{
- struct intel_image_format *f = image->planar_format;
+ const struct intel_image_format *f = image->planar_format;
struct intel_mipmap_tree *planar_mt = NULL;
for (int i = 0; i < f->nplanes; i++) {
image->offsets[index],
width, height, 1,
image->strides[index],
- MIPTREE_LAYOUT_DISABLE_AUX);
+ MIPTREE_CREATE_NO_AUX);
if (mt == NULL)
return NULL;
planar_mt->plane[i - 1] = mt;
}
+ planar_mt->drm_modifier = image->modifier;
+
return planar_mt;
}
+static bool
+create_ccs_buf_for_image(struct brw_context *brw,
+ __DRIimage *image,
+ struct intel_mipmap_tree *mt,
+ enum isl_aux_state initial_state)
+{
+ struct isl_surf temp_ccs_surf;
+
+ /* CCS is only supported for very simple miptrees */
+ assert(image->aux_offset != 0 && image->aux_pitch != 0);
+ assert(image->tile_x == 0 && image->tile_y == 0);
+ assert(mt->surf.samples == 1);
+ assert(mt->surf.levels == 1);
+ assert(mt->surf.logical_level0_px.depth == 1);
+ assert(mt->surf.logical_level0_px.array_len == 1);
+ assert(mt->first_level == 0);
+ assert(mt->last_level == 0);
+
+ /* We shouldn't already have a CCS */
+ assert(!mt->mcs_buf);
+
+ if (!isl_surf_get_ccs_surf(&brw->isl_dev, &mt->surf, &temp_ccs_surf,
+ image->aux_pitch))
+ return false;
+
+ assert(image->aux_offset < image->bo->size);
+ assert(temp_ccs_surf.size <= image->bo->size - image->aux_offset);
+
+ mt->mcs_buf = calloc(sizeof(*mt->mcs_buf), 1);
+ if (mt->mcs_buf == NULL)
+ return false;
+
+ mt->aux_state = create_aux_state_map(mt, initial_state);
+ if (!mt->aux_state) {
+ free(mt->mcs_buf);
+ mt->mcs_buf = NULL;
+ return false;
+ }
+
+ mt->mcs_buf->bo = image->bo;
+ brw_bo_reference(image->bo);
+
+ mt->mcs_buf->offset = image->aux_offset;
+ mt->mcs_buf->size = image->bo->size - image->aux_offset;
+ mt->mcs_buf->pitch = image->aux_pitch;
+ mt->mcs_buf->qpitch = 0;
+ mt->mcs_buf->surf = temp_ccs_surf;
+
+ return true;
+}
+
struct intel_mipmap_tree *
intel_miptree_create_for_dri_image(struct brw_context *brw,
__DRIimage *image, GLenum target,
enum isl_colorspace colorspace,
bool is_winsys_image)
{
- if (image->planar_format && image->planar_format->nplanes > 0) {
+ if (image->planar_format && image->planar_format->nplanes > 1) {
assert(colorspace == ISL_COLORSPACE_NONE ||
colorspace == ISL_COLORSPACE_YUV);
return miptree_create_for_planar_image(brw, image, target);
}
+ if (image->planar_format)
+ assert(image->planar_format->planes[0].dri_format == image->dri_format);
+
mesa_format format = image->format;
switch (colorspace) {
case ISL_COLORSPACE_NONE:
if (!brw->ctx.TextureFormatSupported[format])
return NULL;
+ const struct isl_drm_modifier_info *mod_info =
+ isl_drm_modifier_get_info(image->modifier);
+
+ enum intel_miptree_create_flags mt_create_flags = 0;
+
/* If this image comes in from a window system, we have different
* requirements than if it comes in via an EGL import operation. Window
* system images can use any form of auxiliary compression we wish because
* they get "flushed" before being handed off to the window system and we
- * have the opportunity to do resolves. Window system buffers also may be
- * used for scanout so we need to flag that appropriately.
+ * have the opportunity to do resolves. Non window-system images, on the
+ * other hand, have no resolve point so we can't have aux without a
+ * modifier.
*/
- const uint32_t mt_layout_flags =
- is_winsys_image ? MIPTREE_LAYOUT_FOR_SCANOUT : MIPTREE_LAYOUT_DISABLE_AUX;
+ if (!is_winsys_image)
+ mt_create_flags |= MIPTREE_CREATE_NO_AUX;
+
+ /* If we have a modifier which specifies aux, don't create one yet */
+ if (mod_info && mod_info->aux_usage != ISL_AUX_USAGE_NONE)
+ mt_create_flags |= MIPTREE_CREATE_NO_AUX;
/* Disable creation of the texture's aux buffers because the driver exposes
* no EGL API to manage them. That is, there is no API for resolving the aux
struct intel_mipmap_tree *mt =
intel_miptree_create_for_bo(brw, image->bo, format,
image->offset, image->width, image->height, 1,
- image->pitch, mt_layout_flags);
+ image->pitch, mt_create_flags);
if (mt == NULL)
return NULL;
mt->target = target;
mt->level[0].level_x = image->tile_x;
mt->level[0].level_y = image->tile_y;
+ mt->drm_modifier = image->modifier;
/* From "OES_EGL_image" error reporting. We report GL_INVALID_OPERATION
* for EGL images from non-tile aligned sufaces in gen4 hw and earlier which has
* trouble resolving back to destination image due to alignment issues.
*/
- if (!brw->has_surface_tile_offset) {
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+ if (!devinfo->has_surface_tile_offset) {
uint32_t draw_x, draw_y;
intel_miptree_get_tile_offsets(mt, 0, 0, &draw_x, &draw_y);
}
}
- if (!intel_miptree_alloc_aux(brw, mt)) {
- intel_miptree_release(&mt);
- return NULL;
+ if (mod_info && mod_info->aux_usage != ISL_AUX_USAGE_NONE) {
+ assert(mod_info->aux_usage == ISL_AUX_USAGE_CCS_E);
+
+ mt->aux_usage = mod_info->aux_usage;
+ /* If we are a window system buffer, then we can support fast-clears
+ * even if the modifier doesn't support them by doing a partial resolve
+ * as part of the flush operation.
+ */
+ mt->supports_fast_clear =
+ is_winsys_image || mod_info->supports_clear_color;
+
+ /* We don't know the actual state of the surface when we get it but we
+ * can make a pretty good guess based on the modifier. What we do know
+ * for sure is that it isn't in the AUX_INVALID state, so we just assume
+ * a worst case of compression.
+ */
+ enum isl_aux_state initial_state =
+ isl_drm_modifier_get_default_aux_state(image->modifier);
+
+ if (!create_ccs_buf_for_image(brw, image, mt, initial_state)) {
+ intel_miptree_release(&mt);
+ return NULL;
+ }
}
+ /* Don't assume coherency for imported EGLimages. We don't know what
+ * external clients are going to do with it. They may scan it out.
+ */
+ image->bo->cache_coherent = false;
+
return mt;
}
struct intel_mipmap_tree *mt;
uint32_t depth = 1;
GLenum target = num_samples > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
- const uint32_t layout_flags = MIPTREE_LAYOUT_ACCELERATED_UPLOAD |
- MIPTREE_LAYOUT_TILING_ANY;
mt = intel_miptree_create(brw, target, format, 0, 0,
width, height, depth, num_samples,
- layout_flags);
+ MIPTREE_CREATE_BUSY);
if (!mt)
goto fail;
struct intel_mipmap_tree *mt,
GLuint num_samples)
{
- assert(brw->gen >= 7); /* MCS only used on Gen7+ */
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
+ assert(devinfo->gen >= 7); /* MCS only used on Gen7+ */
assert(mt->mcs_buf == NULL);
assert(mt->aux_usage == ISL_AUX_USAGE_MCS);
* fast-clear operation. In that case, being hot in caches more useful.
*/
const uint32_t alloc_flags = mt->aux_usage == ISL_AUX_USAGE_CCS_E ?
- BO_ALLOC_ZEROED : BO_ALLOC_FOR_RENDER;
+ BO_ALLOC_ZEROED : BO_ALLOC_BUSY;
mt->mcs_buf = intel_alloc_aux_buffer(brw, "ccs-miptree",
&temp_ccs_surf, alloc_flags, mt);
if (!mt->mcs_buf) {
free(aux_state);
return false;
}
-
+
mt->aux_state = aux_state;
return true;
struct intel_mipmap_tree *mt,
uint32_t level)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
assert(mt->hiz_buf);
assert(mt->surf.size > 0);
- if (brw->gen >= 8 || brw->is_haswell) {
+ if (devinfo->gen >= 8 || devinfo->is_haswell) {
uint32_t width = minify(mt->surf.phys_level0_sa.width, level);
uint32_t height = minify(mt->surf.phys_level0_sa.height, level);
isl_surf_get_hiz_surf(&brw->isl_dev, &mt->surf, &temp_hiz_surf);
assert(ok);
- const uint32_t alloc_flags = BO_ALLOC_FOR_RENDER;
+ const uint32_t alloc_flags = BO_ALLOC_BUSY;
mt->hiz_buf = intel_alloc_aux_buffer(brw, "hiz-miptree",
&temp_hiz_surf, alloc_flags, mt);
intel_miptree_sample_with_hiz(struct brw_context *brw,
struct intel_mipmap_tree *mt)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
/* It's unclear how well supported sampling from the hiz buffer is on GEN8,
* so keep things conservative for now and never enable it unless we're SKL+.
*/
- if (brw->gen < 9) {
+ if (devinfo->gen < 9) {
return false;
}
return mt->level[level].has_hiz;
}
+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);
+
+ const uint32_t total_num_layers = brw_get_num_logical_layers(mt, 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;
+}
+
bool
intel_miptree_has_color_unresolved(const struct intel_mipmap_tree *mt,
unsigned start_level, unsigned num_levels,
return false;
/* 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++) {
- uint32_t level_layers = get_num_phys_layers(&mt->surf, level);
-
- level_layers = MIN2(num_layers, level_layers);
+ num_levels = miptree_level_range_length(mt, 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(mt, level, start_layer, num_layers);
for (unsigned a = 0; a < level_layers; a++) {
enum isl_aux_state aux_state =
intel_miptree_get_aux_state(mt, level, start_layer + a);
const struct intel_mipmap_tree *mt,
unsigned level, unsigned layer)
{
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
if (!mt->mcs_buf)
return;
/* Fast color clear is supported for mipmapped surfaces only on Gen8+. */
- assert(brw->gen >= 8 ||
+ assert(devinfo->gen >= 8 ||
(level == 0 && mt->first_level == 0 && mt->last_level == 0));
/* Compression of arrayed msaa surfaces is supported. */
return;
/* Fast color clear is supported for non-msaa arrays only on Gen8+. */
- assert(brw->gen >= 8 ||
+ assert(devinfo->gen >= 8 ||
(layer == 0 &&
mt->surf.logical_level0_px.depth == 1 &&
mt->surf.logical_level0_px.array_len == 1));
switch (aux_state) {
case ISL_AUX_STATE_CLEAR:
- case ISL_AUX_STATE_COMPRESSED_CLEAR:
+ case ISL_AUX_STATE_PARTIAL_CLEAR:
if (!ccs_supported)
return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
else
case ISL_AUX_STATE_PASS_THROUGH:
return BLORP_FAST_CLEAR_OP_NONE;
- case ISL_AUX_STATE_PARTIAL_CLEAR:
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;
}
enum isl_aux_usage aux_usage,
bool fast_clear_supported)
{
- assert(aux_usage == ISL_AUX_USAGE_NONE || aux_usage == ISL_AUX_USAGE_CCS_E);
+ /* 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);
- const bool ccs_supported = 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 BLORP_FAST_CLEAR_OP_NONE;
+ else if (aux_usage == ISL_AUX_USAGE_CCS_E)
+ return BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL;
+ else
+ return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
+
case ISL_AUX_STATE_COMPRESSED_CLEAR:
- if (!ccs_supported)
+ if (aux_usage != ISL_AUX_USAGE_CCS_E)
return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
else if (!fast_clear_supported)
return BLORP_FAST_CLEAR_OP_RESOLVE_PARTIAL;
return BLORP_FAST_CLEAR_OP_NONE;
case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
- if (!ccs_supported)
+ if (aux_usage != ISL_AUX_USAGE_CCS_E)
return BLORP_FAST_CLEAR_OP_RESOLVE_FULL;
else
return BLORP_FAST_CLEAR_OP_NONE;
case ISL_AUX_STATE_PASS_THROUGH:
return BLORP_FAST_CLEAR_OP_NONE;
- case ISL_AUX_STATE_PARTIAL_CLEAR:
case ISL_AUX_STATE_RESOLVED:
case ISL_AUX_STATE_AUX_INVALID:
break;
if (mt->aux_usage == ISL_AUX_USAGE_CCS_E) {
switch (aux_state) {
case ISL_AUX_STATE_CLEAR:
- assert(aux_usage == ISL_AUX_USAGE_CCS_E);
- intel_miptree_set_aux_state(brw, mt, level, layer, 1,
- ISL_AUX_STATE_COMPRESSED_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) {
+ intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+ ISL_AUX_STATE_COMPRESSED_CLEAR);
+ } else if (aux_state != ISL_AUX_STATE_PARTIAL_CLEAR) {
+ intel_miptree_set_aux_state(brw, mt, level, layer, 1,
+ ISL_AUX_STATE_PARTIAL_CLEAR);
+ }
break;
case ISL_AUX_STATE_COMPRESSED_CLEAR:
}
break;
- case ISL_AUX_STATE_PARTIAL_CLEAR:
case ISL_AUX_STATE_RESOLVED:
case ISL_AUX_STATE_AUX_INVALID:
unreachable("Invalid aux state for CCS_E");
case ISL_AUX_STATE_CLEAR:
assert(aux_usage == ISL_AUX_USAGE_CCS_D);
intel_miptree_set_aux_state(brw, mt, level, layer, 1,
- ISL_AUX_STATE_COMPRESSED_CLEAR);
+ ISL_AUX_STATE_PARTIAL_CLEAR);
break;
- case ISL_AUX_STATE_COMPRESSED_CLEAR:
+ case ISL_AUX_STATE_PARTIAL_CLEAR:
assert(aux_usage == ISL_AUX_USAGE_CCS_D);
break; /* Nothing to do */
/* Nothing to do */
break;
- case ISL_AUX_STATE_PARTIAL_CLEAR:
+ case ISL_AUX_STATE_COMPRESSED_CLEAR:
case ISL_AUX_STATE_COMPRESSED_NO_CLEAR:
case ISL_AUX_STATE_RESOLVED:
case ISL_AUX_STATE_AUX_INVALID:
}
}
-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);
-
- const uint32_t total_num_layers = get_num_logical_layers(mt, 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;
-}
-
void
intel_miptree_prepare_access(struct brw_context *brw,
struct intel_mipmap_tree *mt,
assert(intel_miptree_level_has_hiz(mt, level));
}
- for (unsigned a = 0; a < num_layers; a++)
- mt->aux_state[level][start_layer + a] = aux_state;
+ for (unsigned a = 0; a < num_layers; a++) {
+ if (mt->aux_state[level][start_layer + a] != aux_state) {
+ mt->aux_state[level][start_layer + a] = aux_state;
+ brw->ctx.NewDriverState |= BRW_NEW_AUX_STATE;
+ }
+ }
}
/* On Gen9 color buffers may be compressed by the hardware (lossless
static bool
can_texture_with_ccs(struct brw_context *brw,
struct intel_mipmap_tree *mt,
- mesa_format view_format)
+ enum isl_format view_format)
{
if (mt->aux_usage != ISL_AUX_USAGE_CCS_E)
return false;
- 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_formats_are_ccs_e_compatible(&brw->screen->devinfo,
- isl_mt_format, isl_view_format)) {
+ mt->surf.format, view_format)) {
perf_debug("Incompatible sampling format (%s) for rbc (%s)\n",
- _mesa_get_format_name(view_format),
+ isl_format_get_layout(view_format)->name,
_mesa_get_format_name(mt->format));
return false;
}
case ISL_AUX_USAGE_CCS_D:
case ISL_AUX_USAGE_CCS_E:
- if (mt->mcs_buf && can_texture_with_ccs(brw, mt, view_format))
+ if (!mt->mcs_buf) {
+ assert(mt->aux_usage == ISL_AUX_USAGE_CCS_D);
+ return ISL_AUX_USAGE_NONE;
+ }
+
+ /* 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 (!intel_miptree_has_color_unresolved(mt, 0, INTEL_REMAINING_LEVELS,
+ 0, INTEL_REMAINING_LAYERS))
+ return ISL_AUX_USAGE_NONE;
+
+ if (can_texture_with_ccs(brw, mt, view_format))
return ISL_AUX_USAGE_CCS_E;
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);
+}
+
static void
intel_miptree_prepare_texture_slices(struct brw_context *brw,
struct intel_mipmap_tree *mt,
- mesa_format view_format,
+ enum isl_format view_format,
uint32_t start_level, uint32_t num_levels,
uint32_t start_layer, uint32_t num_layers,
bool *aux_supported_out)
* the sampler. If we have a texture view, we would have to perform the
* clear color conversion manually. Just disable clear color.
*/
- if (mt->format != view_format)
+ if (!isl_formats_are_fast_clear_compatible(mt->surf.format, view_format))
clear_supported = false;
intel_miptree_prepare_access(brw, mt, start_level, num_levels,
void
intel_miptree_prepare_texture(struct brw_context *brw,
struct intel_mipmap_tree *mt,
- mesa_format view_format,
+ enum isl_format view_format,
bool *aux_supported_out)
{
intel_miptree_prepare_texture_slices(brw, mt, view_format,
struct intel_mipmap_tree *mt, uint32_t level,
uint32_t start_layer, uint32_t num_layers)
{
- intel_miptree_prepare_texture_slices(brw, mt, mt->format, level, 1,
+ intel_miptree_prepare_texture_slices(brw, mt, mt->surf.format, level, 1,
start_layer, num_layers, NULL);
}
enum isl_aux_usage
intel_miptree_render_aux_usage(struct brw_context *brw,
struct intel_mipmap_tree *mt,
- bool srgb_enabled)
+ bool srgb_enabled, bool blend_enabled)
{
switch (mt->aux_usage) {
case ISL_AUX_USAGE_MCS:
return ISL_AUX_USAGE_MCS;
case ISL_AUX_USAGE_CCS_D:
- /* If FRAMEBUFFER_SRGB is used on Gen9+ then we need to resolve any of
- * the single-sampled color renderbuffers because the CCS buffer isn't
- * supported for SRGB formats. This only matters if FRAMEBUFFER_SRGB is
- * enabled because otherwise the surface state will be programmed with
- * the linear equivalent format anyway.
- */
- if (srgb_enabled &&
- _mesa_get_srgb_format_linear(mt->format) != mt->format) {
- return ISL_AUX_USAGE_NONE;
- } else if (!mt->mcs_buf) {
- return ISL_AUX_USAGE_NONE;
- } else {
- return ISL_AUX_USAGE_CCS_D;
- }
+ return mt->mcs_buf ? ISL_AUX_USAGE_CCS_D : ISL_AUX_USAGE_NONE;
case ISL_AUX_USAGE_CCS_E: {
- /* Lossless compression is not supported for SRGB formats, it
- * should be impossible to get here with such surfaces.
+ mesa_format mesa_format =
+ srgb_enabled ? mt->format :_mesa_get_srgb_format_linear(mt->format);
+ enum isl_format isl_format = brw_isl_format_for_mesa_format(mesa_format);
+
+ /* If the format supports CCS_E, then we can just use it */
+ if (isl_format_supports_ccs_e(&brw->screen->devinfo, isl_format))
+ return ISL_AUX_USAGE_CCS_E;
+
+ /* Otherwise, we have to fall back to CCS_D */
+
+ /* 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.
*/
- assert(!srgb_enabled ||
- _mesa_get_srgb_format_linear(mt->format) == mt->format);
+ if (blend_enabled && isl_format_is_srgb(isl_format) &&
+ !isl_color_value_is_zero_one(mt->fast_clear_color, isl_format))
+ return ISL_AUX_USAGE_NONE;
- return ISL_AUX_USAGE_CCS_E;
+ return ISL_AUX_USAGE_CCS_D;
}
default:
intel_miptree_prepare_render(struct brw_context *brw,
struct intel_mipmap_tree *mt, uint32_t level,
uint32_t start_layer, uint32_t layer_count,
- bool srgb_enabled)
+ bool srgb_enabled, bool blend_enabled)
{
enum isl_aux_usage aux_usage =
- intel_miptree_render_aux_usage(brw, mt, srgb_enabled);
+ intel_miptree_render_aux_usage(brw, mt, srgb_enabled, blend_enabled);
intel_miptree_prepare_access(brw, mt, level, 1, start_layer, layer_count,
aux_usage, aux_usage != ISL_AUX_USAGE_NONE);
}
intel_miptree_finish_render(struct brw_context *brw,
struct intel_mipmap_tree *mt, uint32_t level,
uint32_t start_layer, uint32_t layer_count,
- bool srgb_enabled)
+ bool srgb_enabled, bool blend_enabled)
{
assert(_mesa_is_format_color_format(mt->format));
enum isl_aux_usage aux_usage =
- intel_miptree_render_aux_usage(brw, mt, srgb_enabled);
+ intel_miptree_render_aux_usage(brw, mt, srgb_enabled, blend_enabled);
intel_miptree_finish_write(brw, mt, level, start_layer, layer_count,
aux_usage);
}
}
}
+void
+intel_miptree_prepare_external(struct brw_context *brw,
+ struct intel_mipmap_tree *mt)
+{
+ enum isl_aux_usage aux_usage = ISL_AUX_USAGE_NONE;
+ bool supports_fast_clear = false;
+
+ const struct isl_drm_modifier_info *mod_info =
+ isl_drm_modifier_get_info(mt->drm_modifier);
+
+ if (mod_info && mod_info->aux_usage != ISL_AUX_USAGE_NONE) {
+ /* CCS_E is the only supported aux for external images and it's only
+ * supported on very simple images.
+ */
+ assert(mod_info->aux_usage == ISL_AUX_USAGE_CCS_E);
+ assert(_mesa_is_format_color_format(mt->format));
+ assert(mt->first_level == 0 && mt->last_level == 0);
+ assert(mt->surf.logical_level0_px.depth == 1);
+ assert(mt->surf.logical_level0_px.array_len == 1);
+ assert(mt->surf.samples == 1);
+ assert(mt->mcs_buf != NULL);
+
+ aux_usage = mod_info->aux_usage;
+ supports_fast_clear = mod_info->supports_clear_color;
+ }
+
+ intel_miptree_prepare_access(brw, mt, 0, INTEL_REMAINING_LEVELS,
+ 0, INTEL_REMAINING_LAYERS,
+ aux_usage, supports_fast_clear);
+}
+
+void
+intel_miptree_finish_external(struct brw_context *brw,
+ struct intel_mipmap_tree *mt)
+{
+ if (!mt->mcs_buf)
+ return;
+
+ /* We just got this image in from the window system via glxBindTexImageEXT
+ * or similar and have no idea what the actual aux state is other than that
+ * we aren't in AUX_INVALID. Reset the aux state to the default for the
+ * image's modifier.
+ */
+ enum isl_aux_state default_aux_state =
+ isl_drm_modifier_get_default_aux_state(mt->drm_modifier);
+ assert(mt->last_level == mt->first_level);
+ intel_miptree_set_aux_state(brw, mt, 0, 0, INTEL_REMAINING_LAYERS,
+ default_aux_state);
+}
+
/**
* Make it possible to share the BO backing the given miptree with another
* process or another miptree.
*/
free(mt->aux_state);
mt->aux_state = NULL;
+ brw->ctx.NewDriverState |= BRW_NEW_AUX_STATE;
}
if (mt->hiz_buf) {
*/
free(mt->aux_state);
mt->aux_state = NULL;
+ brw->ctx.NewDriverState |= BRW_NEW_AUX_STATE;
}
mt->aux_usage = ISL_AUX_USAGE_NONE;
+ mt->supports_fast_clear = false;
}
intel_update_r8stencil(struct brw_context *brw,
struct intel_mipmap_tree *mt)
{
- assert(brw->gen >= 7);
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
+ assert(devinfo->gen >= 7);
struct intel_mipmap_tree *src =
mt->format == MESA_FORMAT_S_UINT8 ? mt : mt->stencil_mt;
- if (!src || brw->gen >= 8 || !src->r8stencil_needs_update)
+ if (!src || devinfo->gen >= 8 || !src->r8stencil_needs_update)
return;
assert(src->surf.size > 0);
if (!mt->r8stencil_mt) {
- assert(brw->gen > 6); /* Handle MIPTREE_LAYOUT_GEN6_HIZ_STENCIL */
+ assert(devinfo->gen > 6); /* Handle MIPTREE_LAYOUT_GEN6_HIZ_STENCIL */
mt->r8stencil_mt = make_surface(
brw,
src->target,
src->surf.samples,
ISL_TILING_Y0_BIT,
ISL_SURF_USAGE_TEXTURE_BIT,
- BO_ALLOC_FOR_RENDER, 0, NULL);
+ BO_ALLOC_BUSY, 0, NULL);
assert(mt->r8stencil_mt);
}
/* last_level */ 0,
map->w, map->h, 1,
/* samples */ 1,
- MIPTREE_LAYOUT_TILING_NONE);
+ MIPTREE_CREATE_LINEAR);
if (!map->linear_mt) {
fprintf(stderr, "Failed to allocate blit temporary\n");
unsigned int level,
unsigned int slice)
{
- if (brw->has_llc &&
+ const struct gen_device_info *devinfo = &brw->screen->devinfo;
+
+ if (devinfo->has_llc &&
/* It's probably not worth swapping to the blit ring because of
* all the overhead involved.
*/
!mt->compressed &&
(mt->surf.tiling == ISL_TILING_X ||
/* Prior to Sandybridge, the blitter can't handle Y tiling */
- (brw->gen >= 6 && mt->surf.tiling == ISL_TILING_Y0) ||
+ (devinfo->gen >= 6 && mt->surf.tiling == ISL_TILING_Y0) ||
/* Fast copy blit on skl+ supports all tiling formats. */
- brw->gen >= 9) &&
+ devinfo->gen >= 9) &&
can_blit_slice(mt, level, slice))
return true;