anv/meta: Implement CmdFillBuffer
authorJason Ekstrand <jason.ekstrand@intel.com>
Wed, 20 Jan 2016 00:17:13 +0000 (16:17 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Wed, 20 Jan 2016 00:53:35 +0000 (16:53 -0800)
src/vulkan/anv_meta.c
src/vulkan/anv_meta_clear.c

index 87728943190b320aa04e000d3afcbd5910030f5a..7d8403f0e339aed385e7ba14e0475ee45abdac63 100644 (file)
@@ -1384,16 +1384,6 @@ void anv_CmdUpdateBuffer(
    stub();
 }
 
-void anv_CmdFillBuffer(
-    VkCommandBuffer                             commandBuffer,
-    VkBuffer                                    destBuffer,
-    VkDeviceSize                                destOffset,
-    VkDeviceSize                                fillSize,
-    uint32_t                                    data)
-{
-   stub();
-}
-
 void anv_CmdResolveImage(
     VkCommandBuffer                             commandBuffer,
     VkImage                                     srcImage,
index 1bc470fb5de617f8632a6b050aa8ab60a1d000dd..6ba27b97fe2af4962ba202b188a7dca05ebc63de 100644 (file)
@@ -1015,3 +1015,117 @@ void anv_CmdClearAttachments(
 
    meta_clear_end(&saved_state, cmd_buffer);
 }
+
+static void
+do_buffer_fill(struct anv_cmd_buffer *cmd_buffer,
+               struct anv_bo *dest, uint64_t dest_offset,
+               int width, int height, VkFormat fill_format, uint32_t data)
+{
+   VkDevice vk_device = anv_device_to_handle(cmd_buffer->device);
+
+   VkImageCreateInfo image_info = {
+      .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+      .imageType = VK_IMAGE_TYPE_2D,
+      .format = fill_format,
+      .extent = {
+         .width = width,
+         .height = height,
+         .depth = 1,
+      },
+      .mipLevels = 1,
+      .arrayLayers = 1,
+      .samples = 1,
+      .tiling = VK_IMAGE_TILING_LINEAR,
+      .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+      .flags = 0,
+   };
+
+   VkImage dest_image;
+   image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+   anv_CreateImage(vk_device, &image_info,
+                   &cmd_buffer->pool->alloc, &dest_image);
+
+   /* We could use a vk call to bind memory, but that would require
+    * creating a dummy memory object etc. so there's really no point.
+    */
+   anv_image_from_handle(dest_image)->bo = dest;
+   anv_image_from_handle(dest_image)->offset = dest_offset;
+
+   const VkClearValue clear_value = {
+      .color = {
+         .uint32 = { data, data, data, data }
+      }
+   };
+
+   const VkImageSubresourceRange range = {
+      .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+      .baseMipLevel = 0,
+      .levelCount = 1,
+      .baseArrayLayer = 0,
+      .layerCount = 1,
+   };
+
+   anv_cmd_clear_image(cmd_buffer, anv_image_from_handle(dest_image),
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                       &clear_value, 1, &range);
+}
+
+void anv_CmdFillBuffer(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    dstBuffer,
+    VkDeviceSize                                dstOffset,
+    VkDeviceSize                                fillSize,
+    uint32_t                                    data)
+{
+   ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);
+   ANV_FROM_HANDLE(anv_buffer, dst_buffer, dstBuffer);
+   struct anv_meta_saved_state saved_state;
+
+   meta_clear_begin(&saved_state, cmd_buffer);
+
+   VkFormat format;
+   int bs;
+   if ((fillSize & 15) == 0 && (dstOffset & 15) == 0) {
+      format = VK_FORMAT_R32G32B32A32_UINT;
+      bs = 16;
+   } else if ((fillSize & 7) == 0 && (dstOffset & 15) == 0) {
+      format = VK_FORMAT_R32G32_UINT;
+      bs = 8;
+   } else {
+      assert((fillSize & 3) == 0 && (dstOffset & 3) == 0);
+      format = VK_FORMAT_R32_UINT;
+      bs = 4;
+   }
+
+   /* This is maximum possible width/height our HW can handle */
+   const uint64_t max_surface_dim = 1 << 14;
+
+   /* First, we make a bunch of max-sized copies */
+   const uint64_t max_fill_size = max_surface_dim * max_surface_dim * bs;
+   while (fillSize > max_fill_size) {
+      do_buffer_fill(cmd_buffer, dst_buffer->bo,
+                     dst_buffer->offset + dstOffset,
+                     max_surface_dim, max_surface_dim, format, data);
+      fillSize -= max_fill_size;
+      dstOffset += max_fill_size;
+   }
+
+   uint64_t height = fillSize / (max_surface_dim * bs);
+   assert(height < max_surface_dim);
+   if (height != 0) {
+      const uint64_t rect_fill_size = height * max_surface_dim * bs;
+      do_buffer_fill(cmd_buffer, dst_buffer->bo,
+                     dst_buffer->offset + dstOffset,
+                     max_surface_dim, height, format, data);
+      fillSize -= rect_fill_size;
+      dstOffset += rect_fill_size;
+   }
+
+   if (fillSize != 0) {
+      do_buffer_fill(cmd_buffer, dst_buffer->bo,
+                     dst_buffer->offset + dstOffset,
+                     fillSize / bs, 1, format, data);
+   }
+
+   meta_clear_end(&saved_state, cmd_buffer);
+}