1 /*
2 * Copyright © 2015 Intel Corporation
3 *
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:
10 *
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
13 * Software.
14 *
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
21 * IN THE SOFTWARE.
22 */
23
24 #include "anv_private.h"
25
26 #include "util/list.h"
27 #include "util/ralloc.h"
28
29 /* This file contains utility functions for help debugging. They can be
30 * called from GDB or similar to help inspect images and buffers.
31 *
32 * To dump the framebuffers of an application after each render pass, all you
33 * have to do is the following
34 *
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
42 *
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.
48 */
49
50 struct dump_image {
51 struct list_head link;
52
53 const char *filename;
54
55 VkExtent2D extent;
56 VkImage image;
57 VkDeviceMemory memory;
58 };
59
60 static void
dump_image_init(struct anv_device * device,struct dump_image * image,uint32_t width,uint32_t height,const char * filename)61 dump_image_init(struct anv_device *device, struct dump_image *image,
62 uint32_t width, uint32_t height, const char *filename)
63 {
64 VkDevice vk_device = anv_device_to_handle(device);
65 MAYBE_UNUSED VkResult result;
66
67 image->filename = filename;
68 image->extent = (VkExtent2D) { width, height };
69
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 },
76 .mipLevels = 1,
77 .arrayLayers = 1,
78 .samples = 1,
79 .tiling = VK_IMAGE_TILING_LINEAR,
80 .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
81 .flags = 0,
82 }, NULL, &image->image);
83 assert(result == VK_SUCCESS);
84
85 VkMemoryRequirements reqs;
86 anv_GetImageMemoryRequirements(vk_device, image->image, &reqs);
87
88 result = anv_AllocateMemory(vk_device,
89 &(VkMemoryAllocateInfo) {
90 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
91 .allocationSize = reqs.size,
92 .memoryTypeIndex = 0,
93 }, NULL, &image->memory);
94 assert(result == VK_SUCCESS);
95
96 result = anv_BindImageMemory(vk_device, image->image, image->memory, 0);
97 assert(result == VK_SUCCESS);
98 }
99
100 static void
dump_image_finish(struct anv_device * device,struct dump_image * image)101 dump_image_finish(struct anv_device *device, struct dump_image *image)
102 {
103 VkDevice vk_device = anv_device_to_handle(device);
104
105 anv_DestroyImage(vk_device, image->image, NULL);
106 anv_FreeMemory(vk_device, image->memory, NULL);
107 }
108
109 static void
dump_image_do_blit(struct anv_device * device,struct dump_image * image,struct anv_cmd_buffer * cmd_buffer,struct anv_image * src,VkImageAspectFlagBits aspect,unsigned miplevel,unsigned array_layer)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)
114 {
115 PFN_vkCmdPipelineBarrier CmdPipelineBarrier =
116 (void *)anv_GetDeviceProcAddr(anv_device_to_handle(device),
117 "vkCmdPipelineBarrier");
118
119 CmdPipelineBarrier(anv_cmd_buffer_to_handle(cmd_buffer),
120 VK_PIPELINE_STAGE_TRANSFER_BIT,
121 VK_PIPELINE_STAGE_TRANSFER_BIT,
122 0, 0, NULL, 0, NULL, 1,
123 &(VkImageMemoryBarrier) {
124 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
125 .srcAccessMask = ~0,
126 .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
127 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
128 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
129 .srcQueueFamilyIndex = 0,
130 .dstQueueFamilyIndex = 0,
131 .image = anv_image_to_handle(src),
132 .subresourceRange = (VkImageSubresourceRange) {
133 .aspectMask = aspect,
134 .baseMipLevel = miplevel,
135 .levelCount = 1,
136 .baseArrayLayer = array_layer,
137 .layerCount = 1,
138 },
139 });
140
141 /* We need to do a blit so the image needs to be declared as sampled. The
142 * only thing these are used for is making sure we create the correct
143 * views, so it should be find to just stomp it and set it back.
144 */
145 VkImageUsageFlags old_usage = src->usage;
146 src->usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
147
148 anv_CmdBlitImage(anv_cmd_buffer_to_handle(cmd_buffer),
149 anv_image_to_handle(src), VK_IMAGE_LAYOUT_GENERAL,
150 image->image, VK_IMAGE_LAYOUT_GENERAL, 1,
151 &(VkImageBlit) {
152 .srcSubresource = {
153 .aspectMask = aspect,
154 .mipLevel = miplevel,
155 .baseArrayLayer = array_layer,
156 .layerCount = 1,
157 },
158 .srcOffsets = {
159 { 0, 0, 0 },
160 { image->extent.width, image->extent.height, 1 },
161 },
162 .dstSubresource = {
163 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
164 .mipLevel = 0,
165 .baseArrayLayer = 0,
166 .layerCount = 1,
167 },
168 .dstOffsets = {
169 { 0, 0, 0 },
170 { image->extent.width, image->extent.height, 1 },
171 },
172 }, VK_FILTER_NEAREST);
173
174 src->usage = old_usage;
175
176 CmdPipelineBarrier(anv_cmd_buffer_to_handle(cmd_buffer),
177 VK_PIPELINE_STAGE_TRANSFER_BIT,
178 VK_PIPELINE_STAGE_TRANSFER_BIT,
179 0, 0, NULL, 0, NULL, 1,
180 &(VkImageMemoryBarrier) {
181 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
182 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
183 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
184 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
185 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
186 .srcQueueFamilyIndex = 0,
187 .dstQueueFamilyIndex = 0,
188 .image = image->image,
189 .subresourceRange = (VkImageSubresourceRange) {
190 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
191 .baseMipLevel = 0,
192 .levelCount = 1,
193 .baseArrayLayer = 0,
194 .layerCount = 1,
195 },
196 });
197 }
198
199 static void
dump_image_write_to_ppm(struct anv_device * device,struct dump_image * image)200 dump_image_write_to_ppm(struct anv_device *device, struct dump_image *image)
201 {
202 VkDevice vk_device = anv_device_to_handle(device);
203 MAYBE_UNUSED VkResult result;
204
205 VkMemoryRequirements reqs;
206 anv_GetImageMemoryRequirements(vk_device, image->image, &reqs);
207
208 uint8_t *map;
209 result = anv_MapMemory(vk_device, image->memory, 0, reqs.size, 0, (void **)&map);
210 assert(result == VK_SUCCESS);
211
212 VkSubresourceLayout layout;
213 anv_GetImageSubresourceLayout(vk_device, image->image,
214 &(VkImageSubresource) {
215 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
216 .mipLevel = 0,
217 .arrayLayer = 0,
218 }, &layout);
219
220 map += layout.offset;
221
222 FILE *file = fopen(image->filename, "wb");
223 assert(file);
224
225 uint8_t *row = malloc(image->extent.width * 3);
226 assert(row);
227
228 fprintf(file, "P6\n%d %d\n255\n", image->extent.width, image->extent.height);
229 for (unsigned y = 0; y < image->extent.height; y++) {
230 for (unsigned x = 0; x < image->extent.width; x++) {
231 row[x * 3 + 0] = map[x * 4 + 0];
232 row[x * 3 + 1] = map[x * 4 + 1];
233 row[x * 3 + 2] = map[x * 4 + 2];
234 }
235 fwrite(row, 3, image->extent.width, file);
236
237 map += layout.rowPitch;
238 }
239 free(row);
240 fclose(file);
241
242 anv_UnmapMemory(vk_device, image->memory);
243 }
244
245 void
anv_dump_image_to_ppm(struct anv_device * device,struct anv_image * image,unsigned miplevel,unsigned array_layer,VkImageAspectFlagBits aspect,const char * filename)246 anv_dump_image_to_ppm(struct anv_device *device,
247 struct anv_image *image, unsigned miplevel,
248 unsigned array_layer, VkImageAspectFlagBits aspect,
249 const char *filename)
250 {
251 VkDevice vk_device = anv_device_to_handle(device);
252 MAYBE_UNUSED VkResult result;
253
254 PFN_vkBeginCommandBuffer BeginCommandBuffer =
255 (void *)anv_GetDeviceProcAddr(anv_device_to_handle(device),
256 "vkBeginCommandBuffer");
257 PFN_vkEndCommandBuffer EndCommandBuffer =
258 (void *)anv_GetDeviceProcAddr(anv_device_to_handle(device),
259 "vkEndCommandBuffer");
260
261 const uint32_t width = anv_minify(image->extent.width, miplevel);
262 const uint32_t height = anv_minify(image->extent.height, miplevel);
263
264 struct dump_image dump;
265 dump_image_init(device, &dump, width, height, filename);
266
267 VkCommandPool commandPool;
268 result = anv_CreateCommandPool(vk_device,
269 &(VkCommandPoolCreateInfo) {
270 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
271 .queueFamilyIndex = 0,
272 .flags = 0,
273 }, NULL, &commandPool);
274 assert(result == VK_SUCCESS);
275
276 VkCommandBuffer cmd;
277 result = anv_AllocateCommandBuffers(vk_device,
278 &(VkCommandBufferAllocateInfo) {
279 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
280 .commandPool = commandPool,
281 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
282 .commandBufferCount = 1,
283 }, &cmd);
284 assert(result == VK_SUCCESS);
285
286 result = BeginCommandBuffer(cmd,
287 &(VkCommandBufferBeginInfo) {
288 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
289 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
290 });
291 assert(result == VK_SUCCESS);
292
293 dump_image_do_blit(device, &dump, anv_cmd_buffer_from_handle(cmd), image,
294 aspect, miplevel, array_layer);
295
296 result = EndCommandBuffer(cmd);
297 assert(result == VK_SUCCESS);
298
299 VkFence fence;
300 result = anv_CreateFence(vk_device,
301 &(VkFenceCreateInfo) {
302 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
303 .flags = 0,
304 }, NULL, &fence);
305 assert(result == VK_SUCCESS);
306
307 result = anv_QueueSubmit(anv_queue_to_handle(&device->queue), 1,
308 &(VkSubmitInfo) {
309 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
310 .commandBufferCount = 1,
311 .pCommandBuffers = &cmd,
312 }, fence);
313 assert(result == VK_SUCCESS);
314
315 result = anv_WaitForFences(vk_device, 1, &fence, true, UINT64_MAX);
316 assert(result == VK_SUCCESS);
317
318 anv_DestroyFence(vk_device, fence, NULL);
319 anv_DestroyCommandPool(vk_device, commandPool, NULL);
320
321 dump_image_write_to_ppm(device, &dump);
322 dump_image_finish(device, &dump);
323 }
324
325 static pthread_mutex_t dump_mutex = PTHREAD_MUTEX_INITIALIZER;
326
327 static enum anv_dump_action dump_actions = 0;
328
329 /* Used to prevent recursive dumping */
330 static enum anv_dump_action dump_old_actions;
331
332 struct list_head dump_list;
333 static void *dump_ctx;
334 static struct anv_device *dump_device;
335 static unsigned dump_count;
336
337 void
anv_dump_start(struct anv_device * device,enum anv_dump_action actions)338 anv_dump_start(struct anv_device *device, enum anv_dump_action actions)
339 {
340 pthread_mutex_lock(&dump_mutex);
341
342 dump_device = device;
343 dump_actions = actions;
344 list_inithead(&dump_list);
345 dump_ctx = ralloc_context(NULL);
346 dump_count = 0;
347
348 pthread_mutex_unlock(&dump_mutex);
349 }
350
351 void
anv_dump_finish()352 anv_dump_finish()
353 {
354 anv_DeviceWaitIdle(anv_device_to_handle(dump_device));
355
356 pthread_mutex_lock(&dump_mutex);
357
358 list_for_each_entry(struct dump_image, dump, &dump_list, link) {
359 dump_image_write_to_ppm(dump_device, dump);
360 dump_image_finish(dump_device, dump);
361 }
362
363 dump_actions = 0;
364 dump_device = NULL;
365 list_inithead(&dump_list);
366
367 ralloc_free(dump_ctx);
368 dump_ctx = NULL;
369
370 pthread_mutex_unlock(&dump_mutex);
371 }
372
373 static bool
dump_lock(enum anv_dump_action action)374 dump_lock(enum anv_dump_action action)
375 {
376 if (likely((dump_actions & action) == 0))
377 return false;
378
379 pthread_mutex_lock(&dump_mutex);
380
381 /* Prevent recursive dumping */
382 dump_old_actions = dump_actions;
383 dump_actions = 0;
384
385 return true;
386 }
387
388 static void
dump_unlock()389 dump_unlock()
390 {
391 dump_actions = dump_old_actions;
392 pthread_mutex_unlock(&dump_mutex);
393 }
394
395 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)396 dump_add_image(struct anv_cmd_buffer *cmd_buffer, struct anv_image *image,
397 VkImageAspectFlagBits aspect,
398 unsigned miplevel, unsigned array_layer, const char *filename)
399 {
400 const uint32_t width = anv_minify(image->extent.width, miplevel);
401 const uint32_t height = anv_minify(image->extent.height, miplevel);
402
403 struct dump_image *dump = ralloc(dump_ctx, struct dump_image);
404
405 dump_image_init(cmd_buffer->device, dump, width, height, filename);
406 dump_image_do_blit(cmd_buffer->device, dump, cmd_buffer, image,
407 aspect, miplevel, array_layer);
408
409 list_addtail(&dump->link, &dump_list);
410 }
411
412 void
anv_dump_add_framebuffer(struct anv_cmd_buffer * cmd_buffer,struct anv_framebuffer * fb)413 anv_dump_add_framebuffer(struct anv_cmd_buffer *cmd_buffer,
414 struct anv_framebuffer *fb)
415 {
416 if (!dump_lock(ANV_DUMP_FRAMEBUFFERS_BIT))
417 return;
418
419 unsigned dump_idx = dump_count++;
420
421 for (unsigned i = 0; i < fb->attachment_count; i++) {
422 struct anv_image_view *iview = fb->attachments[i];
423
424 uint32_t b;
425 for_each_bit(b, iview->image->aspects) {
426 VkImageAspectFlagBits aspect = (1 << b);
427 char suffix;
428 switch (aspect) {
429 case VK_IMAGE_ASPECT_COLOR_BIT: suffix = 'c'; break;
430 case VK_IMAGE_ASPECT_DEPTH_BIT: suffix = 'd'; break;
431 case VK_IMAGE_ASPECT_STENCIL_BIT: suffix = 's'; break;
432 default:
433 unreachable("Invalid aspect");
434 }
435
436 char *filename = ralloc_asprintf(dump_ctx, "framebuffer%04d-%d%c.ppm",
437 dump_idx, i, suffix);
438
439 dump_add_image(cmd_buffer, (struct anv_image *)iview->image, aspect,
440 iview->isl.base_level, iview->isl.base_array_layer,
441 filename);
442 }
443 }
444
445 dump_unlock();
446 }
447