radv: optimize CmdClear{Color,DepthStencil}Image() for layered textures
authorSamuel Pitoiset <samuel.pitoiset@gmail.com>
Fri, 23 Nov 2018 16:04:15 +0000 (17:04 +0100)
committerSamuel Pitoiset <samuel.pitoiset@gmail.com>
Thu, 29 Nov 2018 09:18:42 +0000 (10:18 +0100)
If all layers are bound we can perform a fast color or depth clear
instead of iterating over all layers. This has the advantage
to avoid trashing the framebuffer for nothing if you we end up by
doing a fast clear when calling radv_clear_image_layer(), and
clearing all layers in one shot is obviously faster.

Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
src/amd/vulkan/radv_meta_clear.c

index d4da614584be5f62caef2d98c55dcede39a38876..83d4b071d5284ccd090e49a90061714042a31c8b 100644 (file)
@@ -1776,6 +1776,75 @@ radv_clear_image_layer(struct radv_cmd_buffer *cmd_buffer,
        radv_DestroyFramebuffer(device_h, fb,
                                &cmd_buffer->pool->alloc);
 }
+
+/**
+ * Return TRUE if a fast color or depth clear has been performed.
+ */
+static bool
+radv_fast_clear_range(struct radv_cmd_buffer *cmd_buffer,
+                     struct radv_image *image,
+                     VkFormat format,
+                     VkImageLayout image_layout,
+                     const VkImageSubresourceRange *range,
+                     const VkClearValue *clear_val)
+{
+       struct radv_image_view iview;
+
+       radv_image_view_init(&iview, cmd_buffer->device,
+                            &(VkImageViewCreateInfo) {
+                                       .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+                                       .image = radv_image_to_handle(image),
+                                       .viewType = radv_meta_get_view_type(image),
+                                       .format = image->vk_format,
+                                       .subresourceRange = {
+                                       .aspectMask = range->aspectMask,
+                                       .baseMipLevel = range->baseMipLevel,
+                                       .levelCount = range->levelCount,
+                                       .baseArrayLayer = range->baseArrayLayer,
+                                       .layerCount = range->layerCount,
+                                  },
+                            });
+
+       VkClearRect clear_rect = {
+               .rect = {
+                       .offset = { 0, 0 },
+                       .extent = {
+                               radv_minify(image->info.width, range->baseMipLevel),
+                               radv_minify(image->info.height, range->baseMipLevel),
+                       },
+               },
+               .baseArrayLayer = range->baseArrayLayer,
+               .layerCount = range->layerCount,
+       };
+
+       VkClearAttachment clear_att = {
+               .aspectMask = range->aspectMask,
+               .colorAttachment = 0,
+               .clearValue = *clear_val,
+       };
+
+       if (vk_format_is_color(format)) {
+               if (radv_can_fast_clear_color(cmd_buffer, &iview,
+                                             image_layout, &clear_rect,
+                                             clear_att.clearValue.color, 0)) {
+                       radv_fast_clear_color(cmd_buffer, &iview, &clear_att,
+                                             clear_att.colorAttachment,
+                                             NULL, NULL);
+                       return true;
+               }
+       } else {
+               if (radv_can_fast_clear_depth(cmd_buffer, &iview, image_layout,
+                                             range->aspectMask, &clear_rect,
+                                             clear_att.clearValue.depthStencil)) {
+                       radv_fast_clear_depth(cmd_buffer, &iview, &clear_att,
+                                             NULL, NULL);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 static void
 radv_cmd_clear_image(struct radv_cmd_buffer *cmd_buffer,
                     struct radv_image *image,
@@ -1803,18 +1872,31 @@ radv_cmd_clear_image(struct radv_cmd_buffer *cmd_buffer,
                internal_clear_value.color.uint32[0] = (r << 4) | (g & 0xf);
        }
 
+       if (format == VK_FORMAT_R32G32B32_UINT ||
+           format == VK_FORMAT_R32G32B32_SINT ||
+           format == VK_FORMAT_R32G32B32_SFLOAT)
+               cs = true;
+
        for (uint32_t r = 0; r < range_count; r++) {
                const VkImageSubresourceRange *range = &ranges[r];
+
+               /* Try to perform a fast clear first, otherwise fallback to
+                * the legacy path.
+                */
+               if (!cs &&
+                   radv_fast_clear_range(cmd_buffer, image, format,
+                                         image_layout, range,
+                                         &internal_clear_value)) {
+                       continue;
+               }
+
                for (uint32_t l = 0; l < radv_get_levelCount(image, range); ++l) {
                        const uint32_t layer_count = image->type == VK_IMAGE_TYPE_3D ?
                                radv_minify(image->info.depth, range->baseMipLevel + l) :
                                radv_get_layerCount(image, range);
                        for (uint32_t s = 0; s < layer_count; ++s) {
 
-                               if (cs ||
-                                   (format == VK_FORMAT_R32G32B32_UINT ||
-                                    format == VK_FORMAT_R32G32B32_SINT ||
-                                    format == VK_FORMAT_R32G32B32_SFLOAT)) {
+                               if (cs) {
                                        struct radv_meta_blit2d_surf surf;
                                        surf.format = format;
                                        surf.image = image;