From: Jason Ekstrand Date: Tue, 25 Oct 2016 05:03:45 +0000 (-0700) Subject: anv: Add initial support for Sky Lake color compression X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=338cdc172a28266b062794084efb7745f07b02a7;p=mesa.git anv: Add initial support for Sky Lake color compression This commit adds basic support for color compression. For the moment, color compression is only enabled within a render pass and a full resolve is done before the render pass finishes. All texturing operations still happen with CCS disabled. --- diff --git a/src/intel/vulkan/anv_blorp.c b/src/intel/vulkan/anv_blorp.c index 439306be309..e0c36e692f8 100644 --- a/src/intel/vulkan/anv_blorp.c +++ b/src/intel/vulkan/anv_blorp.c @@ -1194,50 +1194,129 @@ void anv_CmdResolveImage( blorp_batch_finish(&batch); } +static void +ccs_resolve_attachment(struct anv_cmd_buffer *cmd_buffer, + struct blorp_batch *batch, + uint32_t att) +{ + struct anv_framebuffer *fb = cmd_buffer->state.framebuffer; + struct anv_attachment_state *att_state = + &cmd_buffer->state.attachments[att]; + + assert(att_state->aux_usage != ISL_AUX_USAGE_CCS_D); + if (att_state->aux_usage != ISL_AUX_USAGE_CCS_E) + return; /* Nothing to resolve */ + + struct anv_render_pass *pass = cmd_buffer->state.pass; + struct anv_subpass *subpass = cmd_buffer->state.subpass; + unsigned subpass_idx = subpass - pass->subpasses; + assert(subpass_idx < pass->subpass_count); + + /* Scan forward to see what all ways this attachment will be used. + * Ideally, we would like to resolve in the same subpass as the last write + * of a particular attachment. That way we only resolve once but it's + * still hot in the cache. + */ + for (uint32_t s = subpass_idx + 1; s < pass->subpass_count; s++) { + enum anv_subpass_usage usage = pass->attachments[att].subpass_usage[s]; + + if (usage & (ANV_SUBPASS_USAGE_DRAW | ANV_SUBPASS_USAGE_RESOLVE_DST)) { + /* We found another subpass that draws to this attachment. We'll + * wait to resolve until then. + */ + return; + } + } + + struct anv_image_view *iview = fb->attachments[att]; + const struct anv_image *image = iview->image; + assert(image->aspects == VK_IMAGE_ASPECT_COLOR_BIT); + + struct blorp_surf surf; + get_blorp_surf_for_anv_image(image, VK_IMAGE_ASPECT_COLOR_BIT, &surf); + surf.aux_surf = &image->aux_surface.isl; + surf.aux_addr = (struct blorp_address) { + .buffer = image->bo, + .offset = image->offset + image->aux_surface.offset, + }; + surf.aux_usage = att_state->aux_usage; + + for (uint32_t layer = 0; layer < fb->layers; layer++) { + blorp_ccs_resolve(batch, &surf, + iview->isl.base_level, + iview->isl.base_array_layer + layer, + iview->isl.format, + BLORP_FAST_CLEAR_OP_RESOLVE_FULL); + } +} + void anv_cmd_buffer_resolve_subpass(struct anv_cmd_buffer *cmd_buffer) { struct anv_framebuffer *fb = cmd_buffer->state.framebuffer; struct anv_subpass *subpass = cmd_buffer->state.subpass; - if (!subpass->has_resolve) - return; struct blorp_batch batch; blorp_batch_init(&cmd_buffer->device->blorp, &batch, cmd_buffer, 0); + /* From the Sky Lake PRM Vol. 7, "Render Target Resolve": + * + * "When performing a render target resolve, PIPE_CONTROL with end of + * pipe sync must be delivered." + */ + cmd_buffer->state.pending_pipe_bits |= ANV_PIPE_CS_STALL_BIT; + for (uint32_t i = 0; i < subpass->color_count; ++i) { - uint32_t src_att = subpass->color_attachments[i]; - uint32_t dst_att = subpass->resolve_attachments[i]; + ccs_resolve_attachment(cmd_buffer, &batch, + subpass->color_attachments[i]); + } - if (dst_att == VK_ATTACHMENT_UNUSED) - continue; + if (subpass->has_resolve) { + for (uint32_t i = 0; i < subpass->color_count; ++i) { + uint32_t src_att = subpass->color_attachments[i]; + uint32_t dst_att = subpass->resolve_attachments[i]; + + if (dst_att == VK_ATTACHMENT_UNUSED) + continue; + + if (cmd_buffer->state.attachments[dst_att].pending_clear_aspects) { + /* From the Vulkan 1.0 spec: + * + * If the first use of an attachment in a render pass is as a + * resolve attachment, then the loadOp is effectively ignored + * as the resolve is guaranteed to overwrite all pixels in the + * render area. + */ + cmd_buffer->state.attachments[dst_att].pending_clear_aspects = 0; + } - if (cmd_buffer->state.attachments[dst_att].pending_clear_aspects) { - /* From the Vulkan 1.0 spec: - * - * If the first use of an attachment in a render pass is as a - * resolve attachment, then the loadOp is effectively ignored - * as the resolve is guaranteed to overwrite all pixels in the - * render area. - */ - cmd_buffer->state.attachments[dst_att].pending_clear_aspects = 0; - } + struct anv_image_view *src_iview = fb->attachments[src_att]; + struct anv_image_view *dst_iview = fb->attachments[dst_att]; - struct anv_image_view *src_iview = fb->attachments[src_att]; - struct anv_image_view *dst_iview = fb->attachments[dst_att]; + const VkRect2D render_area = cmd_buffer->state.render_area; - const VkRect2D render_area = cmd_buffer->state.render_area; + assert(src_iview->aspect_mask == dst_iview->aspect_mask); + resolve_image(&batch, src_iview->image, + src_iview->isl.base_level, + src_iview->isl.base_array_layer, + dst_iview->image, + dst_iview->isl.base_level, + dst_iview->isl.base_array_layer, + src_iview->aspect_mask, + render_area.offset.x, render_area.offset.y, + render_area.offset.x, render_area.offset.y, + render_area.extent.width, render_area.extent.height); - assert(src_iview->aspect_mask == dst_iview->aspect_mask); - resolve_image(&batch, src_iview->image, - src_iview->isl.base_level, src_iview->isl.base_array_layer, - dst_iview->image, - dst_iview->isl.base_level, dst_iview->isl.base_array_layer, - src_iview->aspect_mask, - render_area.offset.x, render_area.offset.y, - render_area.offset.x, render_area.offset.y, - render_area.extent.width, render_area.extent.height); + /* From the Sky Lake PRM Vol. 7, "Render Target Resolve": + * + * "When performing a render target resolve, PIPE_CONTROL with end + * of pipe sync must be delivered." + */ + cmd_buffer->state.pending_pipe_bits |= ANV_PIPE_CS_STALL_BIT; + + ccs_resolve_attachment(cmd_buffer, &batch, dst_att); + } } blorp_batch_finish(&batch); diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c index b9bf6b81799..1fd0434d756 100644 --- a/src/intel/vulkan/anv_image.c +++ b/src/intel/vulkan/anv_image.c @@ -176,23 +176,32 @@ make_surface(const struct anv_device *dev, /* Add a HiZ surface to a depth buffer that will be used for rendering. */ - if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT && - (image->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - + if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) { /* Allow the user to control HiZ enabling. Disable by default on gen7 * because resolves are not currently implemented pre-BDW. */ - if (!env_var_as_boolean("INTEL_VK_HIZ", dev->info.gen >= 8)) { + if (!(image->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + /* It will never be used as an attachment, HiZ is pointless. */ + } else if (!env_var_as_boolean("INTEL_VK_HIZ", dev->info.gen >= 8)) { anv_finishme("Implement gen7 HiZ"); } else if (vk_info->mipLevels > 1) { anv_finishme("Test multi-LOD HiZ"); } else if (dev->info.gen == 8 && vk_info->samples > 1) { anv_finishme("Test gen8 multisampled HiZ"); } else { + assert(image->aux_surface.isl.size == 0); isl_surf_get_hiz_surf(&dev->isl_dev, &image->depth_surface.isl, &image->aux_surface.isl); add_surface(image, &image->aux_surface); } + } else if (aspect == VK_IMAGE_ASPECT_COLOR_BIT && vk_info->samples == 1) { + if (dev->info.gen >= 9 && !unlikely(INTEL_DEBUG & DEBUG_NO_RBC)) { + assert(image->aux_surface.isl.size == 0); + ok = isl_surf_get_ccs_surf(&dev->isl_dev, &anv_surf->isl, + &image->aux_surface.isl); + if (ok) + add_surface(image, &image->aux_surface); + } } return VK_SUCCESS; diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index ce8ceb2005e..bb7837e3c0a 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1083,6 +1083,7 @@ void anv_dynamic_state_copy(struct anv_dynamic_state *dest, * The clear value is valid only if there exists a pending clear. */ struct anv_attachment_state { + enum isl_aux_usage aux_usage; struct anv_state color_rt_state; VkImageAspectFlags pending_clear_aspects; diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c index 6349705350b..dc97f03f66c 100644 --- a/src/intel/vulkan/genX_cmd_buffer.c +++ b/src/intel/vulkan/genX_cmd_buffer.c @@ -165,6 +165,7 @@ add_surface_state_reloc(struct anv_cmd_buffer *cmd_buffer, static void add_image_view_relocs(struct anv_cmd_buffer *cmd_buffer, const struct anv_image_view *iview, + enum isl_aux_usage aux_usage, struct anv_state state) { const struct isl_device *isl_dev = &cmd_buffer->device->isl_dev; @@ -172,6 +173,41 @@ add_image_view_relocs(struct anv_cmd_buffer *cmd_buffer, anv_reloc_list_add(&cmd_buffer->surface_relocs, &cmd_buffer->pool->alloc, state.offset + isl_dev->ss.addr_offset, iview->bo, iview->offset); + + if (aux_usage != ISL_AUX_USAGE_NONE) { + uint32_t aux_offset = iview->offset + iview->image->aux_surface.offset; + + /* On gen7 and prior, the bottom 12 bits of the MCS base address are + * used to store other information. This should be ok, however, because + * surface buffer addresses are always 4K page alinged. + */ + assert((aux_offset & 0xfff) == 0); + uint32_t *aux_addr_dw = state.map + isl_dev->ss.aux_addr_offset; + aux_offset += *aux_addr_dw & 0xfff; + + anv_reloc_list_add(&cmd_buffer->surface_relocs, &cmd_buffer->pool->alloc, + state.offset + isl_dev->ss.aux_addr_offset, + iview->bo, aux_offset); + } +} + +static enum isl_aux_usage +fb_attachment_get_aux_usage(struct anv_device *device, + struct anv_framebuffer *fb, + uint32_t attachment) +{ + struct anv_image_view *iview = fb->attachments[attachment]; + + if (iview->image->aux_surface.isl.size == 0) + return ISL_AUX_USAGE_NONE; /* No aux surface */ + + assert(iview->image->aux_surface.isl.usage & ISL_SURF_USAGE_CCS_BIT); + + if (isl_format_supports_lossless_compression(&device->info, + iview->isl.format)) + return ISL_AUX_USAGE_CCS_E; + + return ISL_AUX_USAGE_NONE; } /** @@ -293,16 +329,24 @@ genX(cmd_buffer_setup_attachments)(struct anv_cmd_buffer *cmd_buffer, assert(iview->vk_format == att->format); if (att_aspects == VK_IMAGE_ASPECT_COLOR_BIT) { + state->attachments[i].aux_usage = + fb_attachment_get_aux_usage(cmd_buffer->device, framebuffer, i); + struct isl_view view = iview->isl; view.usage |= ISL_SURF_USAGE_RENDER_TARGET_BIT; isl_surf_fill_state(isl_dev, state->attachments[i].color_rt_state.map, .surf = &iview->image->color_surface.isl, .view = &view, + .aux_surf = &iview->image->aux_surface.isl, + .aux_usage = state->attachments[i].aux_usage, .mocs = cmd_buffer->device->default_mocs); add_image_view_relocs(cmd_buffer, iview, + state->attachments[i].aux_usage, state->attachments[i].color_rt_state); + } else { + state->attachments[i].aux_usage = ISL_AUX_USAGE_NONE; } } @@ -901,13 +945,15 @@ emit_binding_table(struct anv_cmd_buffer *cmd_buffer, case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: surface_state = desc->image_view->sampler_surface_state; assert(surface_state.alloc_size); - add_image_view_relocs(cmd_buffer, desc->image_view, surface_state); + add_image_view_relocs(cmd_buffer, desc->image_view, + ISL_AUX_USAGE_NONE, surface_state); break; case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { surface_state = desc->image_view->storage_surface_state; assert(surface_state.alloc_size); - add_image_view_relocs(cmd_buffer, desc->image_view, surface_state); + add_image_view_relocs(cmd_buffer, desc->image_view, + ISL_AUX_USAGE_NONE, surface_state); struct brw_image_param *image_param = &cmd_buffer->state.push_constants[stage]->images[image++];