screenshot.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. vk_error vk_render_transition_images_screenshot_swapchain_begin(struct vk_device *dev, struct vk_render_essentials *essentials,
  2. struct vk_image *srcImage, struct vk_image *dstImage){
  3. vk_error retval = VK_ERROR_NONE;
  4. VkResult res;
  5. vkResetCommandBuffer(essentials->cmd_buffer, 0);
  6. VkCommandBufferBeginInfo begin_info = {
  7. .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  8. .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
  9. };
  10. res = vkBeginCommandBuffer(essentials->cmd_buffer, &begin_info);
  11. vk_error_set_vkresult(&retval, res);
  12. if (res)
  13. {
  14. vk_error_printf(&retval, "Couldn't begin recording a command buffer to screenshot image\n");
  15. return retval;
  16. }
  17. VkImageMemoryBarrier image_barrier_dstImage = {
  18. .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  19. .image = dstImage->image,
  20. .srcAccessMask = 0,
  21. .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
  22. .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
  23. .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
  24. .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  25. .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  26. .subresourceRange = {
  27. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  28. .baseMipLevel = 0,
  29. .levelCount = VK_REMAINING_MIP_LEVELS,
  30. .baseArrayLayer = 0,
  31. .layerCount = VK_REMAINING_ARRAY_LAYERS,
  32. },
  33. };
  34. vkCmdPipelineBarrier(essentials->cmd_buffer,
  35. VK_PIPELINE_STAGE_TRANSFER_BIT,
  36. VK_PIPELINE_STAGE_TRANSFER_BIT,
  37. 0,
  38. 0, NULL,
  39. 0, NULL,
  40. 1, &image_barrier_dstImage);
  41. VkImageMemoryBarrier image_barrier_srcImage = {
  42. .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  43. .image = srcImage->image,
  44. .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT,
  45. .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
  46. .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  47. .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  48. .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  49. .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  50. .subresourceRange = {
  51. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  52. .baseMipLevel = 0,
  53. .levelCount = VK_REMAINING_MIP_LEVELS,
  54. .baseArrayLayer = 0,
  55. .layerCount = VK_REMAINING_ARRAY_LAYERS,
  56. },
  57. };
  58. vkCmdPipelineBarrier(essentials->cmd_buffer,
  59. VK_PIPELINE_STAGE_TRANSFER_BIT,
  60. VK_PIPELINE_STAGE_TRANSFER_BIT,
  61. 0,
  62. 0, NULL,
  63. 0, NULL,
  64. 1, &image_barrier_srcImage);
  65. vkEndCommandBuffer(essentials->cmd_buffer);
  66. res = vkResetFences(dev->device, 1, &essentials->exec_fence);
  67. vk_error_set_vkresult(&retval, res);
  68. if (res)
  69. {
  70. vk_error_printf(&retval, "Failed to reset fence\n");
  71. return retval;
  72. }
  73. VkSubmitInfo submit_info = {
  74. .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
  75. .commandBufferCount = 1,
  76. .pCommandBuffers = &essentials->cmd_buffer,
  77. };
  78. vkQueueSubmit(essentials->present_queue, 1, &submit_info, essentials->exec_fence);
  79. res = vkWaitForFences(dev->device, 1, &essentials->exec_fence, true, 1000000000);
  80. vk_error_set_vkresult(&retval, res);
  81. if (res)
  82. {
  83. vk_error_printf(&retval, "Failed to reset fence\n");
  84. return retval;
  85. }
  86. return retval;
  87. }
  88. vk_error vk_render_transition_images_screenshot_swapchain_end(struct vk_device *dev, struct vk_render_essentials *essentials,
  89. struct vk_image *srcImage, struct vk_image *dstImage){
  90. vk_error retval = VK_ERROR_NONE;
  91. VkResult res;
  92. vkResetCommandBuffer(essentials->cmd_buffer, 0);
  93. VkCommandBufferBeginInfo begin_info = {
  94. .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
  95. .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
  96. };
  97. res = vkBeginCommandBuffer(essentials->cmd_buffer, &begin_info);
  98. vk_error_set_vkresult(&retval, res);
  99. if (res)
  100. {
  101. vk_error_printf(&retval, "Couldn't begin recording a command buffer to screenshot image\n");
  102. return retval;
  103. }
  104. VkImageMemoryBarrier image_barrier_dstImage = {
  105. .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  106. .image = dstImage->image,
  107. .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
  108. .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
  109. .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
  110. .newLayout = VK_IMAGE_LAYOUT_GENERAL,
  111. .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  112. .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  113. .subresourceRange = {
  114. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  115. .baseMipLevel = 0,
  116. .levelCount = VK_REMAINING_MIP_LEVELS,
  117. .baseArrayLayer = 0,
  118. .layerCount = VK_REMAINING_ARRAY_LAYERS,
  119. },
  120. };
  121. vkCmdPipelineBarrier(essentials->cmd_buffer,
  122. VK_PIPELINE_STAGE_TRANSFER_BIT,
  123. VK_PIPELINE_STAGE_TRANSFER_BIT,
  124. 0,
  125. 0, NULL,
  126. 0, NULL,
  127. 1, &image_barrier_dstImage);
  128. VkImageMemoryBarrier image_barrier_srcImage = {
  129. .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
  130. .image = srcImage->image,
  131. .srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
  132. .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
  133. .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  134. .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
  135. .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  136. .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
  137. .subresourceRange = {
  138. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  139. .baseMipLevel = 0,
  140. .levelCount = VK_REMAINING_MIP_LEVELS,
  141. .baseArrayLayer = 0,
  142. .layerCount = VK_REMAINING_ARRAY_LAYERS,
  143. },
  144. };
  145. vkCmdPipelineBarrier(essentials->cmd_buffer,
  146. VK_PIPELINE_STAGE_TRANSFER_BIT,
  147. VK_PIPELINE_STAGE_TRANSFER_BIT,
  148. 0,
  149. 0, NULL,
  150. 0, NULL,
  151. 1, &image_barrier_srcImage);
  152. vkEndCommandBuffer(essentials->cmd_buffer);
  153. res = vkResetFences(dev->device, 1, &essentials->exec_fence);
  154. vk_error_set_vkresult(&retval, res);
  155. if (res)
  156. {
  157. vk_error_printf(&retval, "Failed to reset fence\n");
  158. return retval;
  159. }
  160. VkSubmitInfo submit_info = {
  161. .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
  162. .commandBufferCount = 1,
  163. .pCommandBuffers = &essentials->cmd_buffer,
  164. };
  165. vkQueueSubmit(essentials->present_queue, 1, &submit_info, essentials->exec_fence);
  166. res = vkWaitForFences(dev->device, 1, &essentials->exec_fence, true, 1000000000);
  167. vk_error_set_vkresult(&retval, res);
  168. if (res)
  169. {
  170. vk_error_printf(&retval, "Failed to reset fence\n");
  171. return retval;
  172. }
  173. return retval;
  174. }
  175. // RGBA BMP from https://en.wikipedia.org/wiki/BMP_file_format
  176. unsigned char ev(int32_t v) {
  177. static uint32_t counter = 0;
  178. return (unsigned char)((v) >> ((8*(counter++))%32));
  179. }
  180. void write_bmp(uint32_t w, uint32_t h, uint8_t *rgba) {
  181. FILE *f;
  182. unsigned char *img = NULL;
  183. uint32_t x, y;
  184. uint32_t filesize = 108 + 14 + 4 * w*h;
  185. static int scr_id = 0;
  186. img = (unsigned char *) malloc(4 * w * h);
  187. memset(img, 0, 4 * w * h);
  188. for (int x = 0; x < w; x++) {
  189. for (int y = 0; y < h; y++) {
  190. img[(x + y * w)*4 + 3] = rgba[(x+(h-1-y)*w)*4+0];
  191. img[(x + y * w)*4 + 2] = rgba[(x+(h-1-y)*w)*4+1];
  192. img[(x + y * w)*4 + 1] = rgba[(x+(h-1-y)*w)*4+2];
  193. img[(x + y * w)*4 + 0] = rgba[(x+(h-1-y)*w)*4+3];
  194. }
  195. }
  196. unsigned char bmpfileheader[14] = {'B','M', ev(filesize),ev(filesize),ev(filesize),ev(filesize), 0,0,0,0, 108+14,0,0,0};
  197. unsigned char bmpinfoheader[108] = {108,0,0,0,
  198. ev(w),ev(w),ev(w),ev(w), ev(-((int32_t)h)),ev(-((int32_t)h)),ev(-((int32_t)h)),ev(-((int32_t)h)), 1,0, 32,0, 3,0,0,0, ev(w*h*4),ev(w*h*4),ev(w*h*4),ev(w*h*4),
  199. ev(0x0b13),ev(0x0b13),ev(0x0b13),ev(0x0b13), ev(0x0b13),ev(0x0b13),ev(0x0b13),ev(0x0b13),
  200. 0,0,0,0, 0,0,0,0,
  201. 0,0,0,0xff, 0,0,0xff,0, 0,0xff,0,0, 0xff,0,0,0,
  202. ev(0x57696E20),ev(0x57696E20),ev(0x57696E20),ev(0x57696E20),
  203. 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  204. };
  205. char file_name[80] = {0};
  206. sprintf(file_name, "screenshot_%d.bmp", scr_id++);
  207. f = fopen(file_name, "wb");
  208. fwrite(bmpfileheader, 1, 14, f);
  209. fwrite(bmpinfoheader, 1, 108, f);
  210. for (int i = 0; i < h; i++) {
  211. fwrite(img + (w * (h - i - 1) * 4), 4, w, f);
  212. }
  213. free(img);
  214. fclose(f);
  215. }
  216. vk_error make_screenshot(struct vk_physical_device *phy_dev, struct vk_device *dev, struct vk_swapchain *swapchain, struct vk_render_essentials *essentials, uint32_t image_index)
  217. {
  218. vk_error retval = VK_ERROR_NONE;
  219. VkResult res;
  220. if (!essentials->first_render)
  221. {
  222. res = vkWaitForFences(dev->device, 1, &essentials->exec_fence, true, 1000000000);
  223. vk_error_set_vkresult(&retval, res);
  224. if (res)
  225. {
  226. vk_error_printf(&retval, "Wait for fence failed\n");
  227. return retval;
  228. }
  229. }
  230. uint32_t support_format_list[4] = {VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM};
  231. bool supported = false;
  232. for (int i = 0; (i < 4)&&(!supported); i++){
  233. if(swapchain->surface_format.format==support_format_list[i])supported=true;
  234. }
  235. supported &= swapchain->surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  236. if(!supported){
  237. vk_error_printf(&retval, "Can not save screenshot, surface has unique format or not supported transfer %lu\n",
  238. (unsigned long)swapchain->surface_format.format);
  239. return retval;
  240. }
  241. struct vk_image srcImage = {
  242. .image = essentials->images[image_index],
  243. };
  244. VkFormat img_format=VK_FORMAT_R8G8B8A8_UNORM; //VK_FORMAT_R8G8B8A8_SRGB
  245. struct vk_image dstImage = {
  246. .format = img_format,
  247. .extent = render_data.main_gbuffers[image_index].surface_size,
  248. .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
  249. .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
  250. .make_view = false,
  251. .host_visible = true,
  252. .anisotropyEnable = true,
  253. .repeat_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT, //VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER //VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
  254. .mipmaps = false,
  255. .linear = true,
  256. };
  257. retval = vk_create_images(phy_dev, dev, &dstImage, 1);
  258. if (!vk_error_is_success(&retval))
  259. {
  260. vk_error_printf(&retval, "Failed to create dstImage for screenshot\n");
  261. return retval;
  262. }
  263. retval = vk_render_transition_images_screenshot_swapchain_begin(dev, essentials, &srcImage, &dstImage);
  264. if (!vk_error_is_success(&retval))
  265. {
  266. return retval;
  267. }
  268. VkImageCopy imageCopyRegion = {
  269. .srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  270. .srcSubresource.layerCount = 1,
  271. .dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  272. .dstSubresource.layerCount = 1,
  273. .extent.width = dstImage.extent.width,
  274. .extent.height = dstImage.extent.height,
  275. .extent.depth = 1,
  276. };
  277. retval = vk_render_copy_image(dev, essentials, &dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &imageCopyRegion, "screenshot");
  278. if (!vk_error_is_success(&retval))
  279. {
  280. vk_error_printf(&retval, "Failed to copy image for screenshot\n");
  281. return retval;
  282. }
  283. retval = vk_render_transition_images_screenshot_swapchain_end(dev, essentials, &srcImage, &dstImage);
  284. if (!vk_error_is_success(&retval))
  285. {
  286. return retval;
  287. }
  288. VkImageSubresource subResource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
  289. VkSubresourceLayout subResourceLayout;
  290. vkGetImageSubresourceLayout(dev->device, dstImage.image, &subResource, &subResourceLayout);
  291. uint8_t* data;
  292. vkMapMemory(dev->device, dstImage.image_mem, 0, VK_WHOLE_SIZE, 0, (void**)&data);
  293. data += subResourceLayout.offset;
  294. int color_order[3] = {0, 1, 2};
  295. if(swapchain->surface_format.format==VK_FORMAT_B8G8R8A8_SRGB || swapchain->surface_format.format==VK_FORMAT_B8G8R8A8_UNORM){
  296. color_order[0]=2; color_order[1]=1; color_order[2]=0;
  297. }
  298. uint8_t *data_rgba;
  299. data_rgba = (uint8_t*) malloc(4 * dstImage.extent.width * dstImage.extent.height);
  300. for (uint32_t y = 0; y < dstImage.extent.height; y++)
  301. {
  302. uint8_t *row = (uint8_t*)data;
  303. for (uint32_t x = 0; x < dstImage.extent.width; x++)
  304. {
  305. data_rgba[(x+y*dstImage.extent.width)*4+0] = (uint8_t)row[x*4+color_order[0]];
  306. data_rgba[(x+y*dstImage.extent.width)*4+1] = (uint8_t)row[x*4+color_order[1]];
  307. data_rgba[(x+y*dstImage.extent.width)*4+2] = (uint8_t)row[x*4+color_order[2]];
  308. data_rgba[(x+y*dstImage.extent.width)*4+3] = (uint8_t)row[x*4+3];
  309. }
  310. data += subResourceLayout.rowPitch;
  311. }
  312. write_bmp(dstImage.extent.width, dstImage.extent.height, data_rgba);
  313. printf("screenshot done\n");
  314. free(data_rgba);
  315. vkUnmapMemory(dev->device, dstImage.image_mem);
  316. vk_free_images(dev, &dstImage, 1);
  317. return retval;
  318. }