2 * Copyright © 2015 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 #include "anv_private.h"
26 #include "util/list.h"
27 #include "util/ralloc.h"
29 /* This file contains utility functions for help debugging. They can be
30 * called from GDB or similar to help inspect images and buffers.
32 * To dump the framebuffers of an application after each render pass, all you
33 * have to do is the following
35 * 1) Start the application in GDB
36 * 2) Run until you get to the point where the rendering errors occur
37 * 3) Pause in GDB and set a breakpoint in anv_QueuePresentKHR
38 * 4) Continue until it reaches anv_QueuePresentKHR
39 * 5) Call anv_dump_start(queue->device, ANV_DUMP_FRAMEBUFFERS_BIT)
40 * 6) Continue until the next anv_QueuePresentKHR call
41 * 7) Call anv_dump_finish() to complete the dump and write files
43 * While it's a bit manual, the process does allow you to do some very
44 * valuable debugging by dumping every render target at the end of every
45 * render pass. It's worth noting that this assumes that the application
46 * creates all of the command buffers more-or-less in-order and between the
47 * two anv_QueuePresentKHR calls.
51 struct list_head link
;
57 VkDeviceMemory memory
;
61 dump_image_init(struct anv_device
*device
, struct dump_image
*image
,
62 uint32_t width
, uint32_t height
, const char *filename
)
64 VkDevice vk_device
= anv_device_to_handle(device
);
65 MAYBE_UNUSED VkResult result
;
67 image
->filename
= filename
;
68 image
->extent
= (VkExtent2D
) { width
, height
};
70 result
= anv_CreateImage(vk_device
,
71 &(VkImageCreateInfo
) {
72 .sType
= VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
,
73 .imageType
= VK_IMAGE_TYPE_2D
,
74 .format
= VK_FORMAT_R8G8B8A8_UNORM
,
75 .extent
= (VkExtent3D
) { width
, height
, 1 },
79 .tiling
= VK_IMAGE_TILING_LINEAR
,
80 .usage
= VK_IMAGE_USAGE_TRANSFER_DST_BIT
,
82 }, NULL
, &image
->image
);
83 assert(result
== VK_SUCCESS
);
85 VkMemoryRequirements reqs
;
86 anv_GetImageMemoryRequirements(vk_device
, image
->image
, &reqs
);
88 result
= anv_AllocateMemory(vk_device
,
89 &(VkMemoryAllocateInfo
) {
90 .sType
= VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
,
91 .allocationSize
= reqs
.size
,
93 }, NULL
, &image
->memory
);
94 assert(result
== VK_SUCCESS
);
96 result
= anv_BindImageMemory(vk_device
, image
->image
, image
->memory
, 0);
97 assert(result
== VK_SUCCESS
);
101 dump_image_finish(struct anv_device
*device
, struct dump_image
*image
)
103 VkDevice vk_device
= anv_device_to_handle(device
);
105 anv_DestroyImage(vk_device
, image
->image
, NULL
);
106 anv_FreeMemory(vk_device
, image
->memory
, NULL
);
110 dump_image_do_blit(struct anv_device
*device
, struct dump_image
*image
,
111 struct anv_cmd_buffer
*cmd_buffer
, struct anv_image
*src
,
112 VkImageAspectFlagBits aspect
,
113 unsigned miplevel
, unsigned array_layer
)
115 ANV_CALL(CmdPipelineBarrier
)(anv_cmd_buffer_to_handle(cmd_buffer
),
116 VK_PIPELINE_STAGE_TRANSFER_BIT
,
117 VK_PIPELINE_STAGE_TRANSFER_BIT
,
118 0, 0, NULL
, 0, NULL
, 1,
119 &(VkImageMemoryBarrier
) {
120 .sType
= VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
,
122 .dstAccessMask
= VK_ACCESS_TRANSFER_READ_BIT
,
123 .oldLayout
= VK_IMAGE_LAYOUT_GENERAL
,
124 .newLayout
= VK_IMAGE_LAYOUT_GENERAL
,
125 .srcQueueFamilyIndex
= 0,
126 .dstQueueFamilyIndex
= 0,
127 .image
= anv_image_to_handle(src
),
128 .subresourceRange
= (VkImageSubresourceRange
) {
129 .aspectMask
= aspect
,
130 .baseMipLevel
= miplevel
,
132 .baseArrayLayer
= array_layer
,
137 /* We need to do a blit so the image needs to be declared as sampled. The
138 * only thing these are used for is making sure we create the correct
139 * views, so it should be find to just stomp it and set it back.
141 VkImageUsageFlags old_usage
= src
->usage
;
142 src
->usage
|= VK_IMAGE_USAGE_SAMPLED_BIT
;
144 anv_CmdBlitImage(anv_cmd_buffer_to_handle(cmd_buffer
),
145 anv_image_to_handle(src
), VK_IMAGE_LAYOUT_GENERAL
,
146 image
->image
, VK_IMAGE_LAYOUT_GENERAL
, 1,
149 .aspectMask
= aspect
,
150 .mipLevel
= miplevel
,
151 .baseArrayLayer
= array_layer
,
156 { image
->extent
.width
, image
->extent
.height
, 1 },
159 .aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
,
166 { image
->extent
.width
, image
->extent
.height
, 1 },
168 }, VK_FILTER_NEAREST
);
170 src
->usage
= old_usage
;
172 ANV_CALL(CmdPipelineBarrier
)(anv_cmd_buffer_to_handle(cmd_buffer
),
173 VK_PIPELINE_STAGE_TRANSFER_BIT
,
174 VK_PIPELINE_STAGE_TRANSFER_BIT
,
175 true, 0, NULL
, 0, NULL
, 1,
176 &(VkImageMemoryBarrier
) {
177 .sType
= VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
,
178 .srcAccessMask
= VK_ACCESS_HOST_READ_BIT
,
179 .dstAccessMask
= VK_ACCESS_TRANSFER_WRITE_BIT
,
180 .oldLayout
= VK_IMAGE_LAYOUT_GENERAL
,
181 .newLayout
= VK_IMAGE_LAYOUT_GENERAL
,
182 .srcQueueFamilyIndex
= 0,
183 .dstQueueFamilyIndex
= 0,
184 .image
= image
->image
,
185 .subresourceRange
= (VkImageSubresourceRange
) {
186 .aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
,
196 dump_image_write_to_ppm(struct anv_device
*device
, struct dump_image
*image
)
198 VkDevice vk_device
= anv_device_to_handle(device
);
199 MAYBE_UNUSED VkResult result
;
201 VkMemoryRequirements reqs
;
202 anv_GetImageMemoryRequirements(vk_device
, image
->image
, &reqs
);
205 result
= anv_MapMemory(vk_device
, image
->memory
, 0, reqs
.size
, 0, (void **)&map
);
206 assert(result
== VK_SUCCESS
);
208 VkSubresourceLayout layout
;
209 anv_GetImageSubresourceLayout(vk_device
, image
->image
,
210 &(VkImageSubresource
) {
211 .aspectMask
= VK_IMAGE_ASPECT_COLOR_BIT
,
216 map
+= layout
.offset
;
218 FILE *file
= fopen(image
->filename
, "wb");
221 uint8_t *row
= malloc(image
->extent
.width
* 3);
224 fprintf(file
, "P6\n%d %d\n255\n", image
->extent
.width
, image
->extent
.height
);
225 for (unsigned y
= 0; y
< image
->extent
.height
; y
++) {
226 for (unsigned x
= 0; x
< image
->extent
.width
; x
++) {
227 row
[x
* 3 + 0] = map
[x
* 4 + 0];
228 row
[x
* 3 + 1] = map
[x
* 4 + 1];
229 row
[x
* 3 + 2] = map
[x
* 4 + 2];
231 fwrite(row
, 3, image
->extent
.width
, file
);
233 map
+= layout
.rowPitch
;
238 anv_UnmapMemory(vk_device
, image
->memory
);
242 anv_dump_image_to_ppm(struct anv_device
*device
,
243 struct anv_image
*image
, unsigned miplevel
,
244 unsigned array_layer
, VkImageAspectFlagBits aspect
,
245 const char *filename
)
247 VkDevice vk_device
= anv_device_to_handle(device
);
248 MAYBE_UNUSED VkResult result
;
250 const uint32_t width
= anv_minify(image
->extent
.width
, miplevel
);
251 const uint32_t height
= anv_minify(image
->extent
.height
, miplevel
);
253 struct dump_image dump
;
254 dump_image_init(device
, &dump
, width
, height
, filename
);
256 VkCommandPool commandPool
;
257 result
= anv_CreateCommandPool(vk_device
,
258 &(VkCommandPoolCreateInfo
) {
259 .sType
= VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
,
260 .queueFamilyIndex
= 0,
262 }, NULL
, &commandPool
);
263 assert(result
== VK_SUCCESS
);
266 result
= anv_AllocateCommandBuffers(vk_device
,
267 &(VkCommandBufferAllocateInfo
) {
268 .sType
= VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
,
269 .commandPool
= commandPool
,
270 .level
= VK_COMMAND_BUFFER_LEVEL_PRIMARY
,
271 .commandBufferCount
= 1,
273 assert(result
== VK_SUCCESS
);
275 result
= anv_BeginCommandBuffer(cmd
,
276 &(VkCommandBufferBeginInfo
) {
277 .sType
= VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
,
278 .flags
= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
,
280 assert(result
== VK_SUCCESS
);
282 dump_image_do_blit(device
, &dump
, anv_cmd_buffer_from_handle(cmd
), image
,
283 aspect
, miplevel
, array_layer
);
285 result
= anv_EndCommandBuffer(cmd
);
286 assert(result
== VK_SUCCESS
);
289 result
= anv_CreateFence(vk_device
,
290 &(VkFenceCreateInfo
) {
291 .sType
= VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
,
294 assert(result
== VK_SUCCESS
);
296 result
= anv_QueueSubmit(anv_queue_to_handle(&device
->queue
), 1,
298 .sType
= VK_STRUCTURE_TYPE_SUBMIT_INFO
,
299 .commandBufferCount
= 1,
300 .pCommandBuffers
= &cmd
,
302 assert(result
== VK_SUCCESS
);
304 result
= anv_WaitForFences(vk_device
, 1, &fence
, true, UINT64_MAX
);
305 assert(result
== VK_SUCCESS
);
307 anv_DestroyFence(vk_device
, fence
, NULL
);
308 anv_DestroyCommandPool(vk_device
, commandPool
, NULL
);
310 dump_image_write_to_ppm(device
, &dump
);
311 dump_image_finish(device
, &dump
);
314 static pthread_mutex_t dump_mutex
= PTHREAD_MUTEX_INITIALIZER
;
316 static enum anv_dump_action dump_actions
= 0;
318 /* Used to prevent recursive dumping */
319 static enum anv_dump_action dump_old_actions
;
321 struct list_head dump_list
;
322 static void *dump_ctx
;
323 static struct anv_device
*dump_device
;
324 static unsigned dump_count
;
327 anv_dump_start(struct anv_device
*device
, enum anv_dump_action actions
)
329 pthread_mutex_lock(&dump_mutex
);
331 dump_device
= device
;
332 dump_actions
= actions
;
333 list_inithead(&dump_list
);
334 dump_ctx
= ralloc_context(NULL
);
337 pthread_mutex_unlock(&dump_mutex
);
343 anv_DeviceWaitIdle(anv_device_to_handle(dump_device
));
345 pthread_mutex_lock(&dump_mutex
);
347 list_for_each_entry(struct dump_image
, dump
, &dump_list
, link
) {
348 dump_image_write_to_ppm(dump_device
, dump
);
349 dump_image_finish(dump_device
, dump
);
354 list_inithead(&dump_list
);
356 ralloc_free(dump_ctx
);
359 pthread_mutex_unlock(&dump_mutex
);
363 dump_lock(enum anv_dump_action action
)
365 if (likely((dump_actions
& action
) == 0))
368 pthread_mutex_lock(&dump_mutex
);
370 /* Prevent recursive dumping */
371 dump_old_actions
= dump_actions
;
380 dump_actions
= dump_old_actions
;
381 pthread_mutex_unlock(&dump_mutex
);
385 dump_add_image(struct anv_cmd_buffer
*cmd_buffer
, struct anv_image
*image
,
386 VkImageAspectFlagBits aspect
,
387 unsigned miplevel
, unsigned array_layer
, const char *filename
)
389 const uint32_t width
= anv_minify(image
->extent
.width
, miplevel
);
390 const uint32_t height
= anv_minify(image
->extent
.height
, miplevel
);
392 struct dump_image
*dump
= ralloc(dump_ctx
, struct dump_image
);
394 dump_image_init(cmd_buffer
->device
, dump
, width
, height
, filename
);
395 dump_image_do_blit(cmd_buffer
->device
, dump
, cmd_buffer
, image
,
396 aspect
, miplevel
, array_layer
);
398 list_addtail(&dump
->link
, &dump_list
);
402 anv_dump_add_framebuffer(struct anv_cmd_buffer
*cmd_buffer
,
403 struct anv_framebuffer
*fb
)
405 if (!dump_lock(ANV_DUMP_FRAMEBUFFERS_BIT
))
408 unsigned dump_idx
= dump_count
++;
410 for (unsigned i
= 0; i
< fb
->attachment_count
; i
++) {
411 struct anv_image_view
*iview
= fb
->attachments
[i
];
414 for_each_bit(b
, iview
->image
->aspects
) {
415 VkImageAspectFlagBits aspect
= (1 << b
);
418 case VK_IMAGE_ASPECT_COLOR_BIT
: suffix
= 'c'; break;
419 case VK_IMAGE_ASPECT_DEPTH_BIT
: suffix
= 'd'; break;
420 case VK_IMAGE_ASPECT_STENCIL_BIT
: suffix
= 's'; break;
422 unreachable("Invalid aspect");
425 char *filename
= ralloc_asprintf(dump_ctx
, "framebuffer%04d-%d%c.ppm",
426 dump_idx
, i
, suffix
);
428 dump_add_image(cmd_buffer
, (struct anv_image
*)iview
->image
, aspect
,
429 iview
->base_mip
, iview
->base_layer
, filename
);