diff --git a/vulkan-rs/src/image.rs b/vulkan-rs/src/image.rs index cb94c49..ed2596a 100644 --- a/vulkan-rs/src/image.rs +++ b/vulkan-rs/src/image.rs @@ -5,6 +5,7 @@ use crate::prelude::*; use anyhow::Result; use std::cmp; +use std::path::Path; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -776,6 +777,88 @@ impl Image { VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL => VK_ACCESS_SHADER_READ_BIT.into(), } } + + pub fn to_file(self: &Arc, path: impl AsRef) -> Result<()> { + let buffer = self.copy_image_to_buffer()?; + let memory = buffer.map_complete()?; + + let image = image::RgbaImage::from_raw( + self.width, + self.height, + memory.iter().map(|&v| v).collect(), + ) + .ok_or(anyhow::anyhow!( + "failed to create image from raw while saving to file: {:?}", + path.as_ref() + ))?; + + image.save(path)?; + + Ok(()) + } + + fn copy_image_to_buffer(self: &Arc) -> Result>> { + let buffer = Buffer::builder() + .set_usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .set_memory_usage(MemoryUsage::GpuToCpu) + .set_size((self.width * self.height * 4) as VkDeviceSize) + .build(self.device.clone())?; + + let command_buffer = + CommandBuffer::new_primary().build(self.device.clone(), self.queue.clone())?; + + SingleSubmit::builder(&command_buffer, &self.queue, |recorder| { + // copy info for copying the content of the buffer into the image + let buffer_image_copy = VkBufferImageCopy { + bufferOffset: 0, + bufferRowLength: 0, + bufferImageHeight: 0, + imageSubresource: VkImageSubresourceLayers { + aspectMask: VK_IMAGE_ASPECT_COLOR_BIT.into(), + mipLevel: 0, + baseArrayLayer: 0, + layerCount: 1, + }, + imageOffset: VkOffset3D { x: 0, y: 0, z: 0 }, + imageExtent: VkExtent3D { + width: self.width(), + height: self.height(), + depth: 1, + }, + }; + + // subresource information + let subresource_range = VkImageSubresourceRange { + aspectMask: VK_IMAGE_ASPECT_COLOR_BIT.into(), + baseMipLevel: 0, + levelCount: 1, + baseArrayLayer: 0, + layerCount: 1, + }; + + let current_layout = self.image_layout(); + + recorder.set_image_layout( + self, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + subresource_range.clone(), + ); + + recorder.copy_image_to_buffer( + self, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + &buffer, + &[buffer_image_copy], + ); + + recorder.set_image_layout(self, current_layout, subresource_range); + + Ok(()) + }) + .submit()?; + + Ok(buffer) + } } impl VulkanDevice for Image {