From 5e4f9ea363a638645670abeffce08ed58c37c369 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 26 Jun 2018 09:08:48 -0700 Subject: [PATCH] anv: Implement VK_KHR_depth_stencil_resolve --- src/intel/vulkan/anv_device.c | 28 ++++++ src/intel/vulkan/anv_extensions.py | 1 + src/intel/vulkan/anv_pass.c | 37 +++++++- src/intel/vulkan/anv_private.h | 3 + src/intel/vulkan/genX_cmd_buffer.c | 136 +++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 1 deletion(-) diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c index 523f1483e29..85212074385 100644 --- a/src/intel/vulkan/anv_device.c +++ b/src/intel/vulkan/anv_device.c @@ -1130,6 +1130,34 @@ void anv_GetPhysicalDeviceProperties2( vk_foreach_struct(ext, pProperties->pNext) { switch (ext->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR: { + VkPhysicalDeviceDepthStencilResolvePropertiesKHR *props = + (VkPhysicalDeviceDepthStencilResolvePropertiesKHR *)ext; + + /* We support all of the depth resolve modes */ + props->supportedDepthResolveModes = + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR | + VK_RESOLVE_MODE_AVERAGE_BIT_KHR | + VK_RESOLVE_MODE_MIN_BIT_KHR | + VK_RESOLVE_MODE_MAX_BIT_KHR; + + /* Average doesn't make sense for stencil so we don't support that */ + props->supportedStencilResolveModes = + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + if (pdevice->info.gen >= 8) { + /* The advanced stencil resolve modes currently require stencil + * sampling be supported by the hardware. + */ + props->supportedStencilResolveModes |= + VK_RESOLVE_MODE_MIN_BIT_KHR | + VK_RESOLVE_MODE_MAX_BIT_KHR; + } + + props->independentResolveNone = VK_TRUE; + props->independentResolve = VK_TRUE; + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR: { VkPhysicalDeviceDriverPropertiesKHR *driver_props = (VkPhysicalDeviceDriverPropertiesKHR *) ext; diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py index 388845003aa..2ea4cab0e97 100644 --- a/src/intel/vulkan/anv_extensions.py +++ b/src/intel/vulkan/anv_extensions.py @@ -76,6 +76,7 @@ EXTENSIONS = [ Extension('VK_KHR_bind_memory2', 1, True), Extension('VK_KHR_create_renderpass2', 1, True), Extension('VK_KHR_dedicated_allocation', 1, True), + Extension('VK_KHR_depth_stencil_resolve', 1, True), Extension('VK_KHR_descriptor_update_template', 1, True), Extension('VK_KHR_device_group', 1, True), Extension('VK_KHR_device_group_creation', 1, True), diff --git a/src/intel/vulkan/anv_pass.c b/src/intel/vulkan/anv_pass.c index f0eca41935e..02f2be60e02 100644 --- a/src/intel/vulkan/anv_pass.c +++ b/src/intel/vulkan/anv_pass.c @@ -74,6 +74,10 @@ anv_render_pass_compile(struct anv_render_pass *pass) subpass->depth_stencil_attachment->attachment == VK_ATTACHMENT_UNUSED) subpass->depth_stencil_attachment = NULL; + if (subpass->ds_resolve_attachment && + subpass->ds_resolve_attachment->attachment == VK_ATTACHMENT_UNUSED) + subpass->ds_resolve_attachment = NULL; + for (uint32_t j = 0; j < subpass->attachment_count; j++) { struct anv_subpass_attachment *subpass_att = &subpass->attachments[j]; if (subpass_att->attachment == VK_ATTACHMENT_UNUSED) @@ -116,6 +120,16 @@ anv_render_pass_compile(struct anv_render_pass *pass) color_att->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } } + + if (subpass->ds_resolve_attachment) { + struct anv_subpass_attachment *ds_att = + subpass->depth_stencil_attachment; + UNUSED struct anv_subpass_attachment *resolve_att = + subpass->ds_resolve_attachment; + + assert(resolve_att->usage == VK_IMAGE_USAGE_TRANSFER_DST_BIT); + ds_att->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } } /* From the Vulkan 1.0.39 spec: @@ -342,10 +356,15 @@ VkResult anv_CreateRenderPass( static unsigned num_subpass_attachments2(const VkSubpassDescription2KHR *desc) { + const VkSubpassDescriptionDepthStencilResolveKHR *ds_resolve = + vk_find_struct_const(desc->pNext, + SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR); + return desc->inputAttachmentCount + desc->colorAttachmentCount + (desc->pResolveAttachments ? desc->colorAttachmentCount : 0) + - (desc->pDepthStencilAttachment != NULL); + (desc->pDepthStencilAttachment != NULL) + + (ds_resolve && ds_resolve->pDepthStencilResolveAttachment); } VkResult anv_CreateRenderPass2KHR( @@ -460,6 +479,22 @@ VkResult anv_CreateRenderPass2KHR( .layout = desc->pDepthStencilAttachment->layout, }; } + + const VkSubpassDescriptionDepthStencilResolveKHR *ds_resolve = + vk_find_struct_const(desc->pNext, + SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR); + + if (ds_resolve && ds_resolve->pDepthStencilResolveAttachment) { + subpass->ds_resolve_attachment = subpass_attachments++; + + *subpass->ds_resolve_attachment = (struct anv_subpass_attachment) { + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .attachment = ds_resolve->pDepthStencilResolveAttachment->attachment, + .layout = ds_resolve->pDepthStencilResolveAttachment->layout, + }; + subpass->depth_resolve_mode = ds_resolve->depthResolveMode; + subpass->stencil_resolve_mode = ds_resolve->stencilResolveMode; + } } for (uint32_t i = 0; i < pCreateInfo->dependencyCount; i++) diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 2eeb31695c2..aaa17a68241 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -3235,6 +3235,9 @@ struct anv_subpass { struct anv_subpass_attachment * resolve_attachments; struct anv_subpass_attachment * depth_stencil_attachment; + struct anv_subpass_attachment * ds_resolve_attachment; + VkResolveModeFlagBitsKHR depth_resolve_mode; + VkResolveModeFlagBitsKHR stencil_resolve_mode; uint32_t view_mask; diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c index 11ec153ff88..03ea91aa0f9 100644 --- a/src/intel/vulkan/genX_cmd_buffer.c +++ b/src/intel/vulkan/genX_cmd_buffer.c @@ -3886,6 +3886,23 @@ cmd_buffer_begin_subpass(struct anv_cmd_buffer *cmd_buffer, cmd_buffer_emit_depth_stencil(cmd_buffer); } +static enum blorp_filter +vk_to_blorp_resolve_mode(VkResolveModeFlagBitsKHR vk_mode) +{ + switch (vk_mode) { + case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR: + return BLORP_FILTER_SAMPLE_0; + case VK_RESOLVE_MODE_AVERAGE_BIT_KHR: + return BLORP_FILTER_AVERAGE; + case VK_RESOLVE_MODE_MIN_BIT_KHR: + return BLORP_FILTER_MIN_SAMPLE; + case VK_RESOLVE_MODE_MAX_BIT_KHR: + return BLORP_FILTER_MAX_SAMPLE; + default: + return BLORP_FILTER_NONE; + } +} + static void cmd_buffer_end_subpass(struct anv_cmd_buffer *cmd_buffer) { @@ -3953,6 +3970,125 @@ cmd_buffer_end_subpass(struct anv_cmd_buffer *cmd_buffer) } } + if (subpass->ds_resolve_attachment) { + /* We are about to do some MSAA resolves. We need to flush so that the + * result of writes to the MSAA depth attachments show up in the sampler + * when we blit to the single-sampled resolve target. + */ + cmd_buffer->state.pending_pipe_bits |= + ANV_PIPE_TEXTURE_CACHE_INVALIDATE_BIT | + ANV_PIPE_DEPTH_CACHE_FLUSH_BIT; + + uint32_t src_att = subpass->depth_stencil_attachment->attachment; + uint32_t dst_att = subpass->ds_resolve_attachment->attachment; + + assert(src_att < cmd_buffer->state.pass->attachment_count); + assert(dst_att < cmd_buffer->state.pass->attachment_count); + + 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]; + + const VkRect2D render_area = cmd_buffer->state.render_area; + + if ((src_iview->image->aspects & VK_IMAGE_ASPECT_DEPTH_BIT) && + subpass->depth_resolve_mode != VK_RESOLVE_MODE_NONE_KHR) { + + struct anv_attachment_state *src_state = + &cmd_state->attachments[src_att]; + struct anv_attachment_state *dst_state = + &cmd_state->attachments[dst_att]; + + /* MSAA resolves sample from the source attachment. Transition the + * depth attachment first to get rid of any HiZ that we may not be + * able to handle. + */ + transition_depth_buffer(cmd_buffer, src_iview->image, + src_state->current_layout, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + src_state->aux_usage = + anv_layout_to_aux_usage(&cmd_buffer->device->info, src_iview->image, + VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + src_state->current_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + /* MSAA resolves write to the resolve attachment as if it were any + * other transfer op. Transition the resolve attachment accordingly. + */ + VkImageLayout dst_initial_layout = dst_state->current_layout; + + /* If our render area is the entire size of the image, we're going to + * blow it all away so we can claim the initial layout is UNDEFINED + * and we'll get a HiZ ambiguate instead of a resolve. + */ + if (dst_iview->image->type != VK_IMAGE_TYPE_3D && + render_area.offset.x == 0 && render_area.offset.y == 0 && + render_area.extent.width == dst_iview->extent.width && + render_area.extent.height == dst_iview->extent.height) + dst_initial_layout = VK_IMAGE_LAYOUT_UNDEFINED; + + transition_depth_buffer(cmd_buffer, dst_iview->image, + dst_initial_layout, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + dst_state->aux_usage = + anv_layout_to_aux_usage(&cmd_buffer->device->info, dst_iview->image, + VK_IMAGE_ASPECT_DEPTH_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + dst_state->current_layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + enum blorp_filter filter = + vk_to_blorp_resolve_mode(subpass->depth_resolve_mode); + + anv_image_msaa_resolve(cmd_buffer, + src_iview->image, src_state->aux_usage, + src_iview->planes[0].isl.base_level, + src_iview->planes[0].isl.base_array_layer, + dst_iview->image, dst_state->aux_usage, + dst_iview->planes[0].isl.base_level, + dst_iview->planes[0].isl.base_array_layer, + VK_IMAGE_ASPECT_DEPTH_BIT, + render_area.offset.x, render_area.offset.y, + render_area.offset.x, render_area.offset.y, + render_area.extent.width, + render_area.extent.height, + fb->layers, filter); + } + + if ((src_iview->image->aspects & VK_IMAGE_ASPECT_STENCIL_BIT) && + subpass->stencil_resolve_mode != VK_RESOLVE_MODE_NONE_KHR) { + + enum isl_aux_usage src_aux_usage = ISL_AUX_USAGE_NONE; + enum isl_aux_usage dst_aux_usage = ISL_AUX_USAGE_NONE; + + enum blorp_filter filter = + vk_to_blorp_resolve_mode(subpass->stencil_resolve_mode); + + anv_image_msaa_resolve(cmd_buffer, + src_iview->image, src_aux_usage, + src_iview->planes[0].isl.base_level, + src_iview->planes[0].isl.base_array_layer, + dst_iview->image, dst_aux_usage, + dst_iview->planes[0].isl.base_level, + dst_iview->planes[0].isl.base_array_layer, + VK_IMAGE_ASPECT_STENCIL_BIT, + render_area.offset.x, render_area.offset.y, + render_area.offset.x, render_area.offset.y, + render_area.extent.width, + render_area.extent.height, + fb->layers, filter); + } + } + for (uint32_t i = 0; i < subpass->attachment_count; ++i) { const uint32_t a = subpass->attachments[i].attachment; if (a == VK_ATTACHMENT_UNUSED) -- 2.30.2