From 96fa98c18e54a31622a0dea5516f7db7642ca866 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 27 Jun 2016 11:54:14 -0700 Subject: [PATCH] i965/blorp: Only do offset hacks for fake W-tiling and IMS Since the dawn of time, blorp has used offsets directly to get at different mip levels and array slices of surfaces. This isn't really necessary since we can just use the base level/layer provided in the surface state. While it may have simplified blorp's original design, we haven't been using the blorp path for surface state on gen8 thanks to render compression and there's really no good need for it most of the time. This commit restricts such surface munging to the cases of fake W-tiling and fake interleaved multisampling. Reviewed-by: Topi Pohjolainen --- src/mesa/drivers/dri/i965/brw_blorp.c | 76 ++------ src/mesa/drivers/dri/i965/brw_blorp.h | 6 + src/mesa/drivers/dri/i965/brw_blorp_blit.cpp | 185 +++++++++++++------ 3 files changed, 153 insertions(+), 114 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_blorp.c b/src/mesa/drivers/dri/i965/brw_blorp.c index 1a4579ec165..215f76507f5 100644 --- a/src/mesa/drivers/dri/i965/brw_blorp.c +++ b/src/mesa/drivers/dri/i965/brw_blorp.c @@ -90,7 +90,7 @@ get_image_offset_sa_gen6_stencil(const struct isl_surf *surf, *y_offset_sa = y; } -static void +void blorp_get_image_offset_sa(struct isl_device *dev, const struct isl_surf *surf, uint32_t level, uint32_t layer, uint32_t *x_offset_sa, @@ -100,60 +100,11 @@ blorp_get_image_offset_sa(struct isl_device *dev, const struct isl_surf *surf, get_image_offset_sa_gen6_stencil(surf, level, layer, x_offset_sa, y_offset_sa); } else { - /* Using base_array_layer for Z in 3-D surfaces is a bit abusive, but it - * will go away soon enough. - */ - uint32_t z = 0; - if (surf->dim == ISL_SURF_DIM_3D) { - z = layer; - layer = 0; - } - - isl_surf_get_image_offset_sa(surf, level, layer, z, + isl_surf_get_image_offset_sa(surf, level, layer, 0, x_offset_sa, y_offset_sa); } } -static void -surf_apply_level_layer_offsets(struct isl_device *dev, struct isl_surf *surf, - struct isl_view *view, uint32_t *byte_offset, - uint32_t *tile_x_sa, uint32_t *tile_y_sa) -{ - /* This only makes sense for a single level and array slice */ - assert(view->levels == 1 && view->array_len == 1); - - uint32_t x_offset_sa, y_offset_sa; - blorp_get_image_offset_sa(dev, surf, view->base_level, - view->base_array_layer, - &x_offset_sa, &y_offset_sa); - - isl_tiling_get_intratile_offset_sa(dev, surf->tiling, view->format, - surf->row_pitch, x_offset_sa, y_offset_sa, - byte_offset, tile_x_sa, tile_y_sa); - - /* Now that that's done, we have a very bare 2-D surface */ - surf->dim = ISL_SURF_DIM_2D; - surf->dim_layout = ISL_DIM_LAYOUT_GEN4_2D; - - surf->logical_level0_px.width = - minify(surf->logical_level0_px.width, view->base_level); - surf->logical_level0_px.height = - minify(surf->logical_level0_px.height, view->base_level); - surf->logical_level0_px.depth = 1; - surf->logical_level0_px.array_len = 1; - surf->levels = 1; - - /* Alignment doesn't matter since we have 1 miplevel and 1 array slice so - * just pick something that works for everybody. - */ - surf->image_alignment_el = isl_extent3d(4, 4, 1); - - /* TODO: surf->physcal_level0_extent_sa? */ - - view->base_level = 0; - view->base_array_layer = 0; -} - void brw_blorp_surface_info_init(struct brw_context *brw, struct brw_blorp_surface_info *info, @@ -191,8 +142,6 @@ brw_blorp_surface_info_init(struct brw_context *brw, .format = ISL_FORMAT_UNSUPPORTED, /* Set later */ .base_level = level, .levels = 1, - .base_array_layer = layer / layer_multiplier, - .array_len = 1, .channel_select = { ISL_CHANNEL_SELECT_RED, ISL_CHANNEL_SELECT_GREEN, @@ -201,12 +150,21 @@ brw_blorp_surface_info_init(struct brw_context *brw, }, }; - if (brw->gen >= 8 && !is_render_target && info->surf.dim == ISL_SURF_DIM_3D) { - /* On gen8+ we use actual 3-D textures so we need to pass the layer - * through to the sampler. + if (!is_render_target && + (info->surf.dim == ISL_SURF_DIM_3D || + info->surf.msaa_layout == ISL_MSAA_LAYOUT_ARRAY)) { + /* 3-D textures don't support base_array layer and neither do 2-D + * multisampled textures on IVB so we need to pass it through the + * sampler in those cases. These are also two cases where we are + * guaranteed that we won't be doing any funny surface hacks. */ - info->z_offset = layer; + info->view.base_array_layer = 0; + info->view.array_len = MAX2(info->surf.logical_level0_px.depth, + info->surf.logical_level0_px.array_len); + info->z_offset = layer / layer_multiplier; } else { + info->view.base_array_layer = layer / layer_multiplier; + info->view.array_len = 1; info->z_offset = 0; } @@ -252,10 +210,6 @@ brw_blorp_surface_info_init(struct brw_context *brw, break; } } - - surf_apply_level_layer_offsets(&brw->isl_dev, &info->surf, &info->view, - &info->bo_offset, - &info->tile_x_sa, &info->tile_y_sa); } diff --git a/src/mesa/drivers/dri/i965/brw_blorp.h b/src/mesa/drivers/dri/i965/brw_blorp.h index ec12dfe9365..706d53e55c6 100644 --- a/src/mesa/drivers/dri/i965/brw_blorp.h +++ b/src/mesa/drivers/dri/i965/brw_blorp.h @@ -338,6 +338,12 @@ brw_blorp_compile_nir_shader(struct brw_context *brw, struct nir_shader *nir, struct brw_blorp_prog_data *prog_data, unsigned *program_size); +void +blorp_get_image_offset_sa(struct isl_device *dev, const struct isl_surf *surf, + uint32_t level, uint32_t layer, + uint32_t *x_offset_sa, + uint32_t *y_offset_sa); + uint32_t brw_blorp_emit_surface_state(struct brw_context *brw, const struct brw_blorp_surface_info *surface, diff --git a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp index a175156226f..588b7302f59 100644 --- a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp +++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp @@ -1589,6 +1589,115 @@ swizzle_to_scs(GLenum swizzle) return (enum isl_channel_select)((swizzle + 4) & 7); } +static void +surf_convert_to_single_slice(struct brw_context *brw, + struct brw_blorp_surface_info *info) +{ + /* This only makes sense for a single level and array slice */ + assert(info->view.levels == 1 && info->view.array_len == 1); + + /* Just bail if we have nothing to do. */ + if (info->surf.dim == ISL_SURF_DIM_2D && + info->view.base_level == 0 && info->view.base_array_layer == 0 && + info->surf.levels == 0 && info->surf.logical_level0_px.array_len == 0) + return; + + uint32_t x_offset_sa, y_offset_sa; + blorp_get_image_offset_sa(&brw->isl_dev, &info->surf, info->view.base_level, + info->view.base_array_layer, + &x_offset_sa, &y_offset_sa); + + isl_tiling_get_intratile_offset_sa(&brw->isl_dev, info->surf.tiling, + info->view.format, info->surf.row_pitch, + x_offset_sa, y_offset_sa, + &info->bo_offset, + &info->tile_x_sa, &info->tile_y_sa); + + /* TODO: Once this file gets converted to C, we shouls just use designated + * initializers. + */ + struct isl_surf_init_info init_info = isl_surf_init_info(); + + init_info.dim = ISL_SURF_DIM_2D; + init_info.format = ISL_FORMAT_R8_UINT; + init_info.width = + minify(info->surf.logical_level0_px.width, info->view.base_level); + init_info.height = + minify(info->surf.logical_level0_px.height, info->view.base_level); + init_info.depth = 1; + init_info.levels = 1; + init_info.array_len = 1; + init_info.samples = info->surf.samples; + init_info.min_pitch = info->surf.row_pitch; + init_info.usage = info->surf.usage; + init_info.tiling_flags = 1 << info->surf.tiling; + + isl_surf_init_s(&brw->isl_dev, &info->surf, &init_info); + assert(info->surf.row_pitch == init_info.min_pitch); + + /* The view is also different now. */ + info->view.base_level = 0; + info->view.levels = 1; + info->view.base_array_layer = 0; + info->view.array_len = 1; +} + +static void +surf_fake_interleaved_msaa(struct brw_context *brw, + struct brw_blorp_surface_info *info) +{ + assert(info->surf.msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED); + + /* First, we need to convert it to a simple 1-level 1-layer 2-D surface */ + surf_convert_to_single_slice(brw, info); + + info->surf.logical_level0_px = info->surf.phys_level0_sa; + info->surf.samples = 1; + info->surf.msaa_layout = ISL_MSAA_LAYOUT_NONE; +} + +static void +surf_retile_w_to_y(struct brw_context *brw, + struct brw_blorp_surface_info *info) +{ + assert(info->surf.tiling == ISL_TILING_W); + + /* First, we need to convert it to a simple 1-level 1-layer 2-D surface */ + surf_convert_to_single_slice(brw, info); + + /* On gen7+, we don't have interleaved multisampling for color render + * targets so we have to fake it. + * + * TODO: Are we sure we don't also need to fake it on gen6? + */ + if (brw->gen > 6 && info->surf.msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED) { + info->surf.logical_level0_px = info->surf.phys_level0_sa; + info->surf.samples = 1; + info->surf.msaa_layout = ISL_MSAA_LAYOUT_NONE; + } + + if (brw->gen == 6) { + /* Gen6 stencil buffers have a very large alignment coming in from the + * miptree. It's out-of-bounds for what the surface state can handle. + * Since we have a single layer and level, it doesn't really matter as + * long as we don't pass a bogus value into isl_surf_fill_state(). + */ + info->surf.image_alignment_el = isl_extent3d(4, 2, 1); + } + + /* Now that we've converted everything to a simple 2-D surface with only + * one miplevel, we can go about retiling it. + */ + const unsigned x_align = 8, y_align = info->surf.samples != 0 ? 8 : 4; + info->surf.tiling = ISL_TILING_Y0; + info->surf.logical_level0_px.width = + ALIGN(info->surf.logical_level0_px.width, x_align) * 2; + info->surf.logical_level0_px.height = + ALIGN(info->surf.logical_level0_px.height, y_align) / 2; + info->tile_x_sa *= 2; + info->tile_y_sa /= 2; +} + /** * Note: if the src (or dst) is a 2D multisample array texture on Gen7+ using * INTEL_MSAA_LAYOUT_UMS or INTEL_MSAA_LAYOUT_CMS, src_layer (dst_layer) is @@ -1759,7 +1868,10 @@ brw_blorp_blit_miptrees(struct brw_context *brw, /* For some texture types, we need to pass the layer through the sampler. */ params.wm_inputs.src_z = params.src.z_offset; - if (brw->gen > 6 && dst_mt->msaa_layout == INTEL_MSAA_LAYOUT_IMS) { + if (brw->gen > 6 && + params.dst.surf.msaa_layout == ISL_MSAA_LAYOUT_INTERLEAVED) { + assert(params.dst.surf.samples > 1); + /* We must expand the rectangle we send through the rendering pipeline, * to account for the fact that we are mapping the destination region as * single-sampled when it is in fact multisampled. We must also align @@ -1772,71 +1884,41 @@ brw_blorp_blit_miptrees(struct brw_context *brw, * If it's UMS, then we have no choice but to set up the rendering * pipeline as multisampled. */ - assert(params.dst.surf.msaa_layout = ISL_MSAA_LAYOUT_INTERLEAVED); switch (params.dst.surf.samples) { case 2: params.x0 = ROUND_DOWN_TO(params.x0 * 2, 4); params.y0 = ROUND_DOWN_TO(params.y0, 4); params.x1 = ALIGN(params.x1 * 2, 4); params.y1 = ALIGN(params.y1, 4); - params.dst.surf.logical_level0_px.width *= 2; break; case 4: params.x0 = ROUND_DOWN_TO(params.x0 * 2, 4); params.y0 = ROUND_DOWN_TO(params.y0 * 2, 4); params.x1 = ALIGN(params.x1 * 2, 4); params.y1 = ALIGN(params.y1 * 2, 4); - params.dst.surf.logical_level0_px.width *= 2; - params.dst.surf.logical_level0_px.height *= 2; break; case 8: params.x0 = ROUND_DOWN_TO(params.x0 * 4, 8); params.y0 = ROUND_DOWN_TO(params.y0 * 2, 4); params.x1 = ALIGN(params.x1 * 4, 8); params.y1 = ALIGN(params.y1 * 2, 4); - params.dst.surf.logical_level0_px.width *= 4; - params.dst.surf.logical_level0_px.height *= 2; break; case 16: params.x0 = ROUND_DOWN_TO(params.x0 * 4, 8); params.y0 = ROUND_DOWN_TO(params.y0 * 4, 8); params.x1 = ALIGN(params.x1 * 4, 8); params.y1 = ALIGN(params.y1 * 4, 8); - params.dst.surf.logical_level0_px.width *= 4; - params.dst.surf.logical_level0_px.height *= 4; break; default: unreachable("Unrecognized sample count in brw_blorp_blit_params ctor"); } - /* Gen7's rendering hardware only supports the IMS layout for depth and - * stencil render targets. Blorp always maps its destination surface as - * a color render target (even if it's actually a depth or stencil - * buffer). So if the destination is IMS, we'll have to map it as a - * single-sampled texture and interleave the samples ourselves. - */ - params.dst.surf.samples = 1; - params.dst.surf.msaa_layout = ISL_MSAA_LAYOUT_NONE; + surf_fake_interleaved_msaa(brw, ¶ms.dst); wm_prog_key.use_kill = true; } if (params.dst.surf.tiling == ISL_TILING_W) { - /* We need to fake W-tiling with Y-tiling */ - params.dst.surf.tiling = ISL_TILING_Y0; - - wm_prog_key.dst_tiled_w = true; - - if (params.dst.surf.samples > 1) { - /* If the destination surface is a W-tiled multisampled stencil - * buffer that we're mapping as Y tiled, then we need to arrange for - * the WM program to run once per sample rather than once per pixel, - * because the memory layout of related samples doesn't match between - * W and Y tiling. - */ - wm_prog_key.persample_msaa_dispatch = true; - } - /* We must modify the rectangle we send through the rendering pipeline * (and the size and x/y offset of the destination surface), to account * for the fact that we are mapping it as Y-tiled when it is in fact @@ -1888,39 +1970,36 @@ brw_blorp_blit_miptrees(struct brw_context *brw, params.y0 = ROUND_DOWN_TO(params.y0, y_align) / 2; params.x1 = ALIGN(params.x1, x_align) * 2; params.y1 = ALIGN(params.y1, y_align) / 2; - params.dst.surf.logical_level0_px.width = - ALIGN(params.dst.surf.logical_level0_px.width, x_align) * 2; - params.dst.surf.logical_level0_px.height = - ALIGN(params.dst.surf.logical_level0_px.height, y_align) / 2; - params.dst.tile_x_sa *= 2; - params.dst.tile_y_sa /= 2; + + /* Retile the surface to Y-tiled */ + surf_retile_w_to_y(brw, ¶ms.dst); + + wm_prog_key.dst_tiled_w = true; wm_prog_key.use_kill = true; + + if (params.dst.surf.samples > 1) { + /* If the destination surface is a W-tiled multisampled stencil + * buffer that we're mapping as Y tiled, then we need to arrange for + * the WM program to run once per sample rather than once per pixel, + * because the memory layout of related samples doesn't match between + * W and Y tiling. + */ + wm_prog_key.persample_msaa_dispatch = true; + } } if (brw->gen < 8 && params.src.surf.tiling == ISL_TILING_W) { /* On Haswell and earlier, we have to fake W-tiled sources as Y-tiled. * Broadwell adds support for sampling from stencil. - */ - params.src.surf.tiling = ISL_TILING_Y0; - - wm_prog_key.src_tiled_w = true; - - /* We must modify the size and x/y offset of the source surface to - * account for the fact that we are mapping it as Y-tiled when it is in - * fact W tiled. * * See the comments above concerning x/y offset alignment for the * destination surface. * * TODO: what if this makes the texture size too large? */ - const unsigned x_align = 8, y_align = params.src.surf.samples != 0 ? 8 : 4; - params.src.surf.logical_level0_px.width = - ALIGN(params.src.surf.logical_level0_px.width, x_align) * 2; - params.src.surf.logical_level0_px.height = - ALIGN(params.src.surf.logical_level0_px.height, y_align) / 2; - params.src.tile_x_sa *= 2; - params.src.tile_y_sa /= 2; + surf_retile_w_to_y(brw, ¶ms.src); + + wm_prog_key.src_tiled_w = true; } /* tex_samples and rt_samples are the sample counts that are set up in -- 2.30.2