meta/blit: Rework how format and aspect choices are made
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 31 Dec 2015 21:22:43 +0000 (13:22 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 5 Jan 2016 00:08:05 +0000 (16:08 -0800)
This commit does two things.  First, it introduces choose_* functions for
chosing formats and aspects.  Second, it changes the copy (not blit) code
to use appropreately sized UINT formats for everything except depth.  There
are two main reasons for this:  First, it means that compressed and other
non-renderable texture upload should "just work" because it won't be
tripping over non-renderable formats.  Second, it allows us to easly copy
an RGB buffer to and from an RGBX image because the formats will get
switched over to their UINT variants and the shader will deal with the
extra channel for us.

src/vulkan/anv_meta.c

index d9a5783e3493f6cc7cfbc5c1bc408bd332239e6d..a435c26ee592040245a360b8de5f42dade0f2cf9 100644 (file)
@@ -650,6 +650,10 @@ meta_finish_blit(struct anv_cmd_buffer *cmd_buffer,
 static VkFormat
 vk_format_for_size(int bs)
 {
+   /* Note: We intentionally use the 4-channel formats whenever we can.
+    * This is so that, when we do a RGB <-> RGBX copy, the two formats will
+    * line up even though one of them is 3/4 the size of the other.
+    */
    switch (bs) {
    case 1: return VK_FORMAT_R8_UINT;
    case 2: return VK_FORMAT_R8G8_UINT;
@@ -834,6 +838,50 @@ void anv_CmdCopyBuffer(
    meta_finish_blit(cmd_buffer, &saved_state);
 }
 
+static VkFormat
+choose_iview_format(struct anv_image *image, VkImageAspectFlagBits aspect)
+{
+   assert(__builtin_popcount(aspect) == 1);
+
+   struct isl_surf *surf =
+      &anv_image_get_surface_for_aspect_mask(image, aspect)->isl;
+
+   /* vkCmdCopyImage behaves like memcpy. Therefore we choose identical UINT
+    * formats for the source and destination image views.
+    *
+    * From the Vulkan spec (2015-12-30):
+    *
+    *    vkCmdCopyImage performs image copies in a similar manner to a host
+    *    memcpy. It does not perform general-purpose conversions such as
+    *    scaling, resizing, blending, color-space conversion, or format
+    *    conversions.  Rather, it simply copies raw image data. vkCmdCopyImage
+    *    can copy between images with different formats, provided the formats
+    *    are compatible as defined below.
+    *
+    *    [The spec later defines compatibility as having the same number of
+    *    bytes per block].
+    */
+   return vk_format_for_size(isl_format_layouts[surf->format].bs);
+}
+
+static VkFormat
+choose_buffer_format(struct anv_image *image, VkImageAspectFlagBits aspect)
+{
+   assert(__builtin_popcount(aspect) == 1);
+
+   /* vkCmdCopy* commands behave like memcpy. Therefore we choose
+    * compatable UINT formats for the source and destination image views.
+    *
+    * For the buffer, we go back to the original image format and get a
+    * the format as if it were linear.  This way, for RGB formats, we get
+    * an RGB format here even if the tiled image is RGBA. XXX: This doesn't
+    * work if the buffer is the destination.
+    */
+   enum isl_format linear_format = anv_get_isl_format(image->vk_format, aspect);
+
+   return vk_format_for_size(isl_format_layouts[linear_format].bs);
+}
+
 void anv_CmdCopyImage(
     VkCommandBuffer                             commandBuffer,
     VkImage                                     srcImage,
@@ -852,15 +900,23 @@ void anv_CmdCopyImage(
    meta_prepare_blit(cmd_buffer, &saved_state);
 
    for (unsigned r = 0; r < regionCount; r++) {
+      assert(pRegions[r].srcSubresource.aspectMask ==
+             pRegions[r].dstSubresource.aspectMask);
+
+      VkImageAspectFlags aspect = pRegions[r].srcSubresource.aspectMask;
+
+      VkFormat src_format = choose_iview_format(src_image, aspect);
+      VkFormat dst_format = choose_iview_format(dest_image, aspect);
+
       struct anv_image_view src_iview;
       anv_image_view_init(&src_iview, cmd_buffer->device,
          &(VkImageViewCreateInfo) {
             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
             .image = srcImage,
             .viewType = anv_meta_get_view_type(src_image),
-            .format = src_image->vk_format,
+            .format = src_format,
             .subresourceRange = {
-               .aspectMask = pRegions[r].srcSubresource.aspectMask,
+               .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                .baseMipLevel = pRegions[r].srcSubresource.mipLevel,
                .levelCount = 1,
                .baseArrayLayer = pRegions[r].srcSubresource.baseArrayLayer,
@@ -902,7 +958,7 @@ void anv_CmdCopyImage(
                .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
                .image = destImage,
                .viewType = anv_meta_get_view_type(dest_image),
-               .format = dest_image->vk_format,
+               .format = dst_format,
                .subresourceRange = {
                   .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                   .baseMipLevel = pRegions[r].dstSubresource.mipLevel,
@@ -1067,22 +1123,18 @@ void anv_CmdCopyBufferToImage(
    ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
    ANV_FROM_HANDLE(anv_image, dest_image, destImage);
    VkDevice vk_device = anv_device_to_handle(cmd_buffer->device);
-   const VkFormat orig_format = dest_image->vk_format;
    struct anv_meta_saved_state saved_state;
 
    meta_prepare_blit(cmd_buffer, &saved_state);
 
    for (unsigned r = 0; r < regionCount; r++) {
-      VkFormat proxy_format = orig_format;
-      VkImageAspectFlags proxy_aspect = pRegions[r].imageSubresource.aspectMask;
+      VkImageAspectFlags aspect = pRegions[r].imageSubresource.aspectMask;
 
-      if (orig_format == VK_FORMAT_S8_UINT) {
-         proxy_format = VK_FORMAT_R8_UINT;
-         proxy_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
-      }
+      VkFormat image_format = choose_iview_format(dest_image, aspect);
+      VkFormat buffer_format = choose_buffer_format(dest_image, aspect);
 
       struct anv_image *src_image =
-         make_image_for_buffer(vk_device, srcBuffer, proxy_format,
+         make_image_for_buffer(vk_device, srcBuffer, buffer_format,
                                VK_IMAGE_USAGE_SAMPLED_BIT,
                                dest_image->type, &cmd_buffer->pool->alloc,
                                &pRegions[r]);
@@ -1108,9 +1160,9 @@ void anv_CmdCopyBufferToImage(
                .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
                .image = anv_image_to_handle(src_image),
                .viewType = VK_IMAGE_VIEW_TYPE_2D,
-               .format = proxy_format,
+               .format = buffer_format,
                .subresourceRange = {
-                  .aspectMask = proxy_aspect,
+                  .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                   .baseMipLevel = 0,
                   .levelCount = 1,
                   .baseArrayLayer = 0,
@@ -1125,7 +1177,7 @@ void anv_CmdCopyBufferToImage(
                .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
                .image = anv_image_to_handle(dest_image),
                .viewType = anv_meta_get_view_type(dest_image),
-               .format = proxy_format,
+               .format = image_format,
                .subresourceRange = {
                   .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                   .baseMipLevel = pRegions[r].imageSubresource.mipLevel,
@@ -1188,15 +1240,20 @@ void anv_CmdCopyImageToBuffer(
    meta_prepare_blit(cmd_buffer, &saved_state);
 
    for (unsigned r = 0; r < regionCount; r++) {
+      VkImageAspectFlags aspect = pRegions[r].imageSubresource.aspectMask;
+
+      VkFormat image_format = choose_iview_format(src_image, aspect);
+      VkFormat buffer_format = choose_buffer_format(src_image, aspect);
+
       struct anv_image_view src_iview;
       anv_image_view_init(&src_iview, cmd_buffer->device,
          &(VkImageViewCreateInfo) {
             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
             .image = srcImage,
             .viewType = anv_meta_get_view_type(src_image),
-            .format = src_image->vk_format,
+            .format = image_format,
             .subresourceRange = {
-               .aspectMask = pRegions[r].imageSubresource.aspectMask,
+               .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                .baseMipLevel = pRegions[r].imageSubresource.mipLevel,
                .levelCount = 1,
                .baseArrayLayer = pRegions[r].imageSubresource.baseArrayLayer,
@@ -1205,13 +1262,8 @@ void anv_CmdCopyImageToBuffer(
          },
          cmd_buffer);
 
-      VkFormat dest_format = src_image->vk_format;
-      if (dest_format == VK_FORMAT_S8_UINT) {
-         dest_format = VK_FORMAT_R8_UINT;
-      }
-
       struct anv_image *dest_image =
-         make_image_for_buffer(vk_device, destBuffer, dest_format,
+         make_image_for_buffer(vk_device, destBuffer, buffer_format,
                                VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
                                src_image->type, &cmd_buffer->pool->alloc,
                                &pRegions[r]);
@@ -1235,7 +1287,7 @@ void anv_CmdCopyImageToBuffer(
                .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
                .image = anv_image_to_handle(dest_image),
                .viewType = VK_IMAGE_VIEW_TYPE_2D,
-               .format = dest_format,
+               .format = buffer_format,
                .subresourceRange = {
                   .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
                   .baseMipLevel = 0,