+static void
+dump_image_write_to_ppm(struct anv_device *device, struct dump_image *image)
+{
+ VkDevice vk_device = anv_device_to_handle(device);
+ ASSERTED VkResult result;
+
+ VkMemoryRequirements reqs;
+ anv_GetImageMemoryRequirements(vk_device, image->image, &reqs);
+
+ uint8_t *map;
+ result = anv_MapMemory(vk_device, image->memory, 0, reqs.size, 0, (void **)&map);
+ assert(result == VK_SUCCESS);
+
+ VkSubresourceLayout layout;
+ anv_GetImageSubresourceLayout(vk_device, image->image,
+ &(VkImageSubresource) {
+ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+ .mipLevel = 0,
+ .arrayLayer = 0,
+ }, &layout);
+
+ map += layout.offset;
+
+ FILE *file = fopen(image->filename, "wb");
+ assert(file);
+
+ uint8_t *row = malloc(image->extent.width * 3);
+ assert(row);
+
+ fprintf(file, "P6\n%d %d\n255\n", image->extent.width, image->extent.height);
+ for (unsigned y = 0; y < image->extent.height; y++) {
+ for (unsigned x = 0; x < image->extent.width; x++) {
+ row[x * 3 + 0] = map[x * 4 + 0];
+ row[x * 3 + 1] = map[x * 4 + 1];
+ row[x * 3 + 2] = map[x * 4 + 2];
+ }
+ fwrite(row, 3, image->extent.width, file);
+
+ map += layout.rowPitch;
+ }
+ free(row);
+ fclose(file);
+
+ anv_UnmapMemory(vk_device, image->memory);
+}
+
+void
+anv_dump_image_to_ppm(struct anv_device *device,
+ struct anv_image *image, unsigned miplevel,
+ unsigned array_layer, VkImageAspectFlagBits aspect,
+ const char *filename)
+{
+ VkDevice vk_device = anv_device_to_handle(device);
+ 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);
+
+ struct dump_image dump;
+ dump_image_init(device, &dump, width, height, filename);
+
+ VkCommandPool commandPool;
+ result = anv_CreateCommandPool(vk_device,
+ &(VkCommandPoolCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+ .queueFamilyIndex = 0,
+ .flags = 0,
+ }, NULL, &commandPool);
+ assert(result == VK_SUCCESS);
+
+ VkCommandBuffer cmd;
+ result = anv_AllocateCommandBuffers(vk_device,
+ &(VkCommandBufferAllocateInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+ .commandPool = commandPool,
+ .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+ .commandBufferCount = 1,
+ }, &cmd);
+ assert(result == VK_SUCCESS);
+
+ result = BeginCommandBuffer(cmd,
+ &(VkCommandBufferBeginInfo) {
+ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+ .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
+ });
+ assert(result == VK_SUCCESS);
+
+ dump_image_do_blit(device, &dump, anv_cmd_buffer_from_handle(cmd), image,
+ aspect, miplevel, array_layer);
+
+ result = EndCommandBuffer(cmd);