anv: refresh cached current batch bo after emitting some commands
[mesa.git] / src / intel / vulkan / anv_dump.c
index 0fee93ced0ae14a7c14d28efd018f24ee1385131..f3447f43b2190af65616cfaec9b69abe8b3baa8c 100644 (file)
 
 #include "anv_private.h"
 
+#include "util/list.h"
+#include "util/ralloc.h"
+
 /* This file contains utility functions for help debugging.  They can be
  * called from GDB or similar to help inspect images and buffers.
+ *
+ * To dump the framebuffers of an application after each render pass, all you
+ * have to do is the following
+ *
+ *    1) Start the application in GDB
+ *    2) Run until you get to the point where the rendering errors occur
+ *    3) Pause in GDB and set a breakpoint in anv_QueuePresentKHR
+ *    4) Continue until it reaches anv_QueuePresentKHR
+ *    5) Call anv_dump_start(queue->device, ANV_DUMP_FRAMEBUFFERS_BIT)
+ *    6) Continue until the next anv_QueuePresentKHR call
+ *    7) Call anv_dump_finish() to complete the dump and write files
+ *
+ * While it's a bit manual, the process does allow you to do some very
+ * valuable debugging by dumping every render target at the end of every
+ * render pass.  It's worth noting that this assumes that the application
+ * creates all of the command buffers more-or-less in-order and between the
+ * two anv_QueuePresentKHR calls.
  */
 
 struct dump_image {
+   struct list_head link;
+
    const char *filename;
 
    VkExtent2D extent;
@@ -40,7 +62,7 @@ dump_image_init(struct anv_device *device, struct dump_image *image,
                 uint32_t width, uint32_t height, const char *filename)
 {
    VkDevice vk_device = anv_device_to_handle(device);
-   MAYBE_UNUSED VkResult result;
+   ASSERTED VkResult result;
 
    image->filename = filename;
    image->extent = (VkExtent2D) { width, height };
@@ -90,6 +112,32 @@ dump_image_do_blit(struct anv_device *device, struct dump_image *image,
                    VkImageAspectFlagBits aspect,
                    unsigned miplevel, unsigned array_layer)
 {
+   PFN_vkCmdPipelineBarrier CmdPipelineBarrier =
+      (void *)anv_GetDeviceProcAddr(anv_device_to_handle(device),
+                                    "vkCmdPipelineBarrier");
+
+   CmdPipelineBarrier(anv_cmd_buffer_to_handle(cmd_buffer),
+      VK_PIPELINE_STAGE_TRANSFER_BIT,
+      VK_PIPELINE_STAGE_TRANSFER_BIT,
+      0, 0, NULL, 0, NULL, 1,
+      &(VkImageMemoryBarrier) {
+         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+         .srcAccessMask = ~0,
+         .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
+         .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
+         .newLayout = VK_IMAGE_LAYOUT_GENERAL,
+         .srcQueueFamilyIndex = 0,
+         .dstQueueFamilyIndex = 0,
+         .image = anv_image_to_handle(src),
+         .subresourceRange = (VkImageSubresourceRange) {
+            .aspectMask = aspect,
+            .baseMipLevel = miplevel,
+            .levelCount = 1,
+            .baseArrayLayer = array_layer,
+            .layerCount = 1,
+         },
+      });
+
    /* We need to do a blit so the image needs to be declared as sampled.  The
     * only thing these are used for is making sure we create the correct
     * views, so it should be find to just stomp it and set it back.
@@ -125,14 +173,14 @@ dump_image_do_blit(struct anv_device *device, struct dump_image *image,
 
    src->usage = old_usage;
 
-   ANV_CALL(CmdPipelineBarrier)(anv_cmd_buffer_to_handle(cmd_buffer),
+   CmdPipelineBarrier(anv_cmd_buffer_to_handle(cmd_buffer),
       VK_PIPELINE_STAGE_TRANSFER_BIT,
       VK_PIPELINE_STAGE_TRANSFER_BIT,
-      true, 0, NULL, 0, NULL, 1,
+      0, 0, NULL, 0, NULL, 1,
       &(VkImageMemoryBarrier) {
          .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-         .srcAccessMask = VK_ACCESS_HOST_READ_BIT,
-         .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+         .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+         .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
          .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
          .newLayout = VK_IMAGE_LAYOUT_GENERAL,
          .srcQueueFamilyIndex = 0,
@@ -152,7 +200,7 @@ static void
 dump_image_write_to_ppm(struct anv_device *device, struct dump_image *image)
 {
    VkDevice vk_device = anv_device_to_handle(device);
-   MAYBE_UNUSED VkResult result;
+   ASSERTED VkResult result;
 
    VkMemoryRequirements reqs;
    anv_GetImageMemoryRequirements(vk_device, image->image, &reqs);
@@ -201,7 +249,14 @@ anv_dump_image_to_ppm(struct anv_device *device,
                       const char *filename)
 {
    VkDevice vk_device = anv_device_to_handle(device);
-   MAYBE_UNUSED VkResult result;
+   ASSERTED VkResult result;
+
+   PFN_vkBeginCommandBuffer BeginCommandBuffer =
+      (void *)anv_GetDeviceProcAddr(anv_device_to_handle(device),
+                                    "vkBeginCommandBuffer");
+   PFN_vkEndCommandBuffer EndCommandBuffer =
+      (void *)anv_GetDeviceProcAddr(anv_device_to_handle(device),
+                                    "vkEndCommandBuffer");
 
    const uint32_t width = anv_minify(image->extent.width, miplevel);
    const uint32_t height = anv_minify(image->extent.height, miplevel);
@@ -228,7 +283,7 @@ anv_dump_image_to_ppm(struct anv_device *device,
       }, &cmd);
    assert(result == VK_SUCCESS);
 
-   result = anv_BeginCommandBuffer(cmd,
+   result = BeginCommandBuffer(cmd,
       &(VkCommandBufferBeginInfo) {
          .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
          .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
@@ -238,7 +293,7 @@ anv_dump_image_to_ppm(struct anv_device *device,
    dump_image_do_blit(device, &dump, anv_cmd_buffer_from_handle(cmd), image,
                       aspect, miplevel, array_layer);
 
-   result = anv_EndCommandBuffer(cmd);
+   result = EndCommandBuffer(cmd);
    assert(result == VK_SUCCESS);
 
    VkFence fence;
@@ -266,3 +321,130 @@ anv_dump_image_to_ppm(struct anv_device *device,
    dump_image_write_to_ppm(device, &dump);
    dump_image_finish(device, &dump);
 }
+
+static pthread_mutex_t dump_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static enum anv_dump_action dump_actions = 0;
+
+/* Used to prevent recursive dumping */
+static enum anv_dump_action dump_old_actions;
+
+struct list_head dump_list;
+static void *dump_ctx;
+static struct anv_device *dump_device;
+static unsigned dump_count;
+
+void
+anv_dump_start(struct anv_device *device, enum anv_dump_action actions)
+{
+   pthread_mutex_lock(&dump_mutex);
+
+   dump_device = device;
+   dump_actions = actions;
+   list_inithead(&dump_list);
+   dump_ctx = ralloc_context(NULL);
+   dump_count = 0;
+
+   pthread_mutex_unlock(&dump_mutex);
+}
+
+void
+anv_dump_finish()
+{
+   anv_DeviceWaitIdle(anv_device_to_handle(dump_device));
+
+   pthread_mutex_lock(&dump_mutex);
+
+   list_for_each_entry(struct dump_image, dump, &dump_list, link) {
+      dump_image_write_to_ppm(dump_device, dump);
+      dump_image_finish(dump_device, dump);
+   }
+
+   dump_actions = 0;
+   dump_device = NULL;
+   list_inithead(&dump_list);
+
+   ralloc_free(dump_ctx);
+   dump_ctx = NULL;
+
+   pthread_mutex_unlock(&dump_mutex);
+}
+
+static bool
+dump_lock(enum anv_dump_action action)
+{
+   if (likely((dump_actions & action) == 0))
+      return false;
+
+   pthread_mutex_lock(&dump_mutex);
+
+   /* Prevent recursive dumping */
+   dump_old_actions = dump_actions;
+   dump_actions = 0;
+
+   return true;
+}
+
+static void
+dump_unlock()
+{
+   dump_actions = dump_old_actions;
+   pthread_mutex_unlock(&dump_mutex);
+}
+
+static void
+dump_add_image(struct anv_cmd_buffer *cmd_buffer, struct anv_image *image,
+               VkImageAspectFlagBits aspect,
+               unsigned miplevel, unsigned array_layer, const char *filename)
+{
+   const uint32_t width = anv_minify(image->extent.width, miplevel);
+   const uint32_t height = anv_minify(image->extent.height, miplevel);
+
+   struct dump_image *dump = ralloc(dump_ctx, struct dump_image);
+
+   dump_image_init(cmd_buffer->device, dump, width, height, filename);
+   dump_image_do_blit(cmd_buffer->device, dump, cmd_buffer, image,
+                      aspect, miplevel, array_layer);
+
+   list_addtail(&dump->link, &dump_list);
+}
+
+void
+anv_dump_add_attachments(struct anv_cmd_buffer *cmd_buffer)
+{
+   if (!dump_lock(ANV_DUMP_FRAMEBUFFERS_BIT))
+      return;
+
+   unsigned dump_idx = dump_count++;
+
+   for (unsigned i = 0; i < cmd_buffer->state.pass->attachment_count; i++) {
+      struct anv_image_view *iview = cmd_buffer->state.attachments[i].image_view;
+
+      uint32_t b;
+      for_each_bit(b, iview->image->aspects) {
+         VkImageAspectFlagBits aspect = (1 << b);
+         const char *suffix;
+         switch (aspect) {
+         case VK_IMAGE_ASPECT_COLOR_BIT:       suffix = "c"; break;
+         case VK_IMAGE_ASPECT_DEPTH_BIT:       suffix = "d"; break;
+         case VK_IMAGE_ASPECT_STENCIL_BIT:     suffix = "s"; break;
+         case VK_IMAGE_ASPECT_PLANE_0_BIT:     suffix = "c0"; break;
+         case VK_IMAGE_ASPECT_PLANE_1_BIT:     suffix = "c1"; break;
+         case VK_IMAGE_ASPECT_PLANE_2_BIT:     suffix = "c2"; break;
+         default:
+            unreachable("Invalid aspect");
+         }
+
+         char *filename = ralloc_asprintf(dump_ctx, "attachment%04d-%d%s.ppm",
+                                          dump_idx, i, suffix);
+
+         unsigned plane = anv_image_aspect_to_plane(iview->image->aspects, aspect);
+         dump_add_image(cmd_buffer, (struct anv_image *)iview->image, aspect,
+                        iview->planes[plane].isl.base_level,
+                        iview->planes[plane].isl.base_array_layer,
+                        filename);
+      }
+   }
+
+   dump_unlock();
+}