From 5ffc55b4160f58d86ccb3c513a8584b365f0a639 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Fri, 28 Feb 2025 14:45:43 +0100 Subject: [PATCH] Add first cube map implementation --- vulkan-rs/src/image.rs | 135 ++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 28 deletions(-) diff --git a/vulkan-rs/src/image.rs b/vulkan-rs/src/image.rs index 4920f8d..cca7763 100644 --- a/vulkan-rs/src/image.rs +++ b/vulkan-rs/src/image.rs @@ -13,6 +13,7 @@ enum ImageSourceType { Empty, Raw(Vec), Array(Vec>), + CubeMap([Vec; 6]), } struct ImageCreateInfo { @@ -144,25 +145,25 @@ impl ImageBuilder { Ok(image) } ImageBuilderInternalType::NewImage(info) => match info.source_type { - ImageSourceType::Array(ref array) => { + ImageSourceType::Array(array) => { let arc_image = Self::create_from_source( device, queue, - &info, + info.vk_image_create_info, self.sampler, image_view_ci, self.file_name, )?; - copy_images_to_imagearray(device, queue, &arc_image, array)?; + copy_images_to_image_array(device, queue, &arc_image, &array)?; Ok(arc_image) } - ImageSourceType::Raw(ref raw) => { + ImageSourceType::Raw(raw) => { let arc_image = Self::create_from_source( device, queue, - &info, + info.vk_image_create_info, self.sampler, image_view_ci, self.file_name, @@ -172,9 +173,10 @@ impl ImageBuilder { device, queue, &raw.into_iter() - .map(|&d| RawBuffer { d }) + .map(|d| RawBuffer { d }) .collect::>(), &arc_image, + 0, )?; Ok(arc_image) @@ -183,12 +185,36 @@ impl ImageBuilder { let arc_image = Self::create_from_source( device, queue, - &info, + info.vk_image_create_info, self.sampler, image_view_ci, self.file_name, )?; + Ok(arc_image) + } + ImageSourceType::CubeMap(raw_array) => { + let arc_image = Self::create_from_source( + device, + queue, + info.vk_image_create_info, + self.sampler, + image_view_ci, + self.file_name, + )?; + + for (layer, raw) in raw_array.into_iter().enumerate() { + Self::optimize_fill( + device, + queue, + &raw.into_iter() + .map(|d| RawBuffer { d }) + .collect::>(), + &arc_image, + layer as u32, + )?; + } + Ok(arc_image) } }, @@ -357,6 +383,10 @@ impl ImageBuilder { self } + pub fn get_lod(&self) -> f32 { + self.subresource_range.levelCount as f32 + } + pub fn aspect_mask(mut self, mask: VkImageAspectFlags) -> Self { self.subresource_range.aspectMask = mask.into(); @@ -386,14 +416,14 @@ impl ImageBuilder { fn create_from_source( device: &Arc, queue: &Arc>, - info: &ImageCreateInfo, + info: VkImageCreateInfo, sampler: Option>, mut view_ci: VkImageViewCreateInfo, file_name: Option, ) -> Result> { let format = view_ci.format; - let (image, memory) = Self::create_texture(device, &info.vk_image_create_info)?; + let (image, memory) = Self::create_texture(device, &info)?; view_ci.image = image; @@ -412,16 +442,16 @@ impl ImageBuilder { file_name, format, - image_layout: Mutex::new(info.vk_image_create_info.initialLayout), + image_layout: Mutex::new(info.initialLayout), aspect_mask: view_ci.subresourceRange.aspectMask, - width: info.vk_image_create_info.extent.width, - height: info.vk_image_create_info.extent.height, - layers: info.vk_image_create_info.arrayLayers, - levels: info.vk_image_create_info.mipLevels, - sample_count: info.vk_image_create_info.samples, - usage: info.vk_image_create_info.usage, + width: info.extent.width, + height: info.extent.height, + layers: info.arrayLayers, + levels: info.mipLevels, + sample_count: info.samples, + usage: info.usage, })) } @@ -430,11 +460,7 @@ impl ImageBuilder { image_ci: &VkImageCreateInfo, ) -> Result<(VkImage, Arc>)> { let image = Self::create_image(device, image_ci)?; - let memory = Memory::image_memory( - device, - image, - MemoryUsage::into_vma(Some(MemoryUsage::GpuOnly)), - )?; + let memory = Memory::image_memory(device, image, MemoryUsage::GpuOnly.into())?; Ok((image, memory)) } @@ -451,6 +477,7 @@ impl ImageBuilder { queue: &Arc>, data: &[RawBuffer], image: &Arc, + layer: u32, ) -> Result<()> { let staging_buffer = Buffer::builder() .set_usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT) @@ -458,7 +485,7 @@ impl ImageBuilder { .set_data(data) .build(device.clone())?; - copy_buffer_to_image(device, queue, &staging_buffer, image)?; + copy_buffer_to_image(device, queue, &staging_buffer, image, layer)?; Ok(()) } @@ -624,7 +651,6 @@ impl Image { let array_len = array.len() as u32; let mut create_info = ImageCreateInfo::default(ImageSourceType::Array(array)); create_info.vk_image_create_info.arrayLayers = array_len; - create_info.vk_image_create_info.imageType = VK_IMAGE_TYPE_2D; create_info.vk_image_create_info.extent.width = width; create_info.vk_image_create_info.extent.height = height; create_info.vk_image_create_info.extent.depth = 1; @@ -636,6 +662,56 @@ impl Image { image_builder } + /// Creates an `ImageBuilder` where you can define the image for your needs + /// + /// takes an array of 6 files and setups the `ImageBuilder` to create + /// a single `Arc` with an cube map image created from the provided files + /// + /// # Arguments + /// + /// * `array` - Source images + pub fn cube_map(array: [AssetPath; 6]) -> Result { + let images = array + .into_iter() + .map(|path| { + image::open(&path.full_path()) + .map(|i| i.to_rgba8()) + .map_err(|err| anyhow::Error::new(err).context(path.full_path())) + }) + .collect::>>()?; + + let width = images[0].width(); + let height = images[0].height(); + + if cfg!(debug_assertions) { + for image in &images { + if width != image.width() || height != image.height() { + panic!("images are not equally sized"); + } + } + } + + let mut create_info = ImageCreateInfo::default(ImageSourceType::CubeMap( + images + .into_iter() + .map(|image| image.into_raw()) + .collect::>() + .try_into() + .unwrap(), + )); + create_info.vk_image_create_info.arrayLayers = 6; + create_info.vk_image_create_info.extent.width = width; + create_info.vk_image_create_info.extent.height = height; + create_info.vk_image_create_info.extent.depth = 1; + create_info.vk_image_create_info.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT.into(); + + let mut image_builder = ImageBuilder::new(ImageBuilderInternalType::NewImage(create_info)); + image_builder.view_type = VK_IMAGE_VIEW_TYPE_CUBE; + image_builder.subresource_range.layerCount = 6; + + Ok(image_builder) + } + /// Creates an `ImageBuilder` where you can define the image for your needs /// /// takes raw information to setup `ImageBuilder`, that creates an `Arc` @@ -789,7 +865,7 @@ impl Image { } pub fn to_file(self: &Arc, path: impl AsRef) -> Result<()> { - // check if image is created with correct usage flag that allows transfering data from it + // check if image is created with correct usage flag that allows transferring data from it if (self.usage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0 { return Err(anyhow::anyhow!( "Image has not been create with VK_IMAGE_USAGE_TRANSFER_SRC_BIT flag!" @@ -886,7 +962,7 @@ impl Image { } pub fn copy_buffer_to_image(self: &Arc, buffer: &Arc>) -> Result<()> { - copy_buffer_to_image(&self.device, &self.queue, &buffer, self) + copy_buffer_to_image(&self.device, &self.queue, &buffer, self, 0) } } @@ -955,10 +1031,13 @@ fn copy_buffer_to_image( queue: &Arc>, buffer: &Arc>, image: &Arc, + layer: u32, ) -> Result<()> where T: Copy, { + debug_assert!(layer < image.layers); + // create a new command buffer let command_buffer = CommandBuffer::new_primary().build(device.clone(), queue.clone())?; @@ -976,7 +1055,7 @@ where imageSubresource: VkImageSubresourceLayers { aspectMask: VK_IMAGE_ASPECT_COLOR_BIT.into(), mipLevel: 0, - baseArrayLayer: 0, + baseArrayLayer: layer, layerCount: 1, }, imageOffset: VkOffset3D { x: 0, y: 0, z: 0 }, @@ -993,7 +1072,7 @@ where baseMipLevel: 0, levelCount: image.levels(), baseArrayLayer: 0, - layerCount: 1, + layerCount: image.layers(), }; // set image layout to receive content @@ -1045,7 +1124,7 @@ where Ok(()) } -fn copy_images_to_imagearray( +fn copy_images_to_image_array( device: &Arc, queue: &Arc>, image_array: &Arc,