pub fn enqueue_load_layered_image_2d(
    device_context: &VkDeviceContext,
    upload: &mut VkTransferUpload,
    transfer_queue_family_index: u32,
    dst_queue_family_index: u32,
    decoded_images: &[DecodedImage],
    layer_image_assignments: &[usize],
    create_flags: vk::ImageCreateFlags,
) -> Result<ManuallyDrop<VkImage>, VkUploadError> {
    // All images must have identical mip level count
    #[cfg(debug_assertions)]
    {
        let first = &decoded_images[0];
        for decoded_image in decoded_images {
            assert_eq!(first.mips, decoded_image.mips);
            assert_eq!(first.width, decoded_image.width);
            assert_eq!(first.height, decoded_image.height);
            assert_eq!(first.color_space, decoded_image.color_space);
            assert_eq!(first.data.len(), decoded_image.data.len());
        }
    }

    // Arbitrary, not sure if there is any requirement
    const REQUIRED_ALIGNMENT: usize = 16;

    // Check ahead of time if there is space since we are uploading multiple images
    let has_space_available = upload.has_space_available(
        decoded_images[0].data.len(),
        REQUIRED_ALIGNMENT,
        decoded_images.len(),
    );
    if !has_space_available {
        Err(VkUploadError::BufferFull)?;
    }

    let extent = vk::Extent3D {
        width: decoded_images[0].width,
        height: decoded_images[0].height,
        depth: 1,
    };

    let (mip_level_count, generate_mips) = match decoded_images[0].mips {
        DecodedImageMips::None => (1, false),
        DecodedImageMips::Precomputed(_mip_count) => unimplemented!(), //(info.mip_level_count, false),
        DecodedImageMips::Runtime(mip_count) => (mip_count, true),
    };

    // Push all images into the staging buffer
    let mut layer_offsets = Vec::default();
    for decoded_image in decoded_images {
        layer_offsets.push(upload.push(&decoded_image.data, REQUIRED_ALIGNMENT)?);
    }

    let mut image_usage = vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED;
    if generate_mips {
        image_usage |= vk::ImageUsageFlags::TRANSFER_SRC;
    };

    let format = match decoded_images[0].color_space {
        DecodedImageColorSpace::Linear => vk::Format::R8G8B8A8_UNORM,
        DecodedImageColorSpace::Srgb => vk::Format::R8G8B8A8_SRGB,
    };

    // Allocate an image
    let image = ManuallyDrop::new(VkImage::new(
        device_context,
        vk_mem::MemoryUsage::GpuOnly,
        create_flags,
        image_usage,
        extent,
        format,
        vk::ImageTiling::OPTIMAL,
        vk::SampleCountFlags::TYPE_1,
        layer_image_assignments.len() as u32,
        mip_level_count,
        vk::MemoryPropertyFlags::DEVICE_LOCAL,
    )?);

    //
    // Write into the transfer command buffer
    // - transition destination memory to receive the data
    // - copy the data
    // - transition the destination to the graphics queue
    //

    // Mip 0, all layers
    let subresource_range = vk::ImageSubresourceRange::builder()
        .base_array_layer(0)
        .layer_count(layer_image_assignments.len() as u32)
        .base_mip_level(0)
        .level_count(1)
        .aspect_mask(vk::ImageAspectFlags::COLOR)
        .build();

    cmd_image_memory_barrier(
        device_context.device(),
        upload.transfer_command_buffer(),
        &[image.image()],
        ImageMemoryBarrierType::PreUpload,
        transfer_queue_family_index,
        transfer_queue_family_index,
        &subresource_range,
    );

    for (layer_index, image_index) in layer_image_assignments.iter().enumerate() {
        let layer_subresource_layers = vk::ImageSubresourceLayers::builder()
            .aspect_mask(vk::ImageAspectFlags::COLOR)
            .base_array_layer(layer_index as u32)
            .layer_count(1)
            .mip_level(0)
            .build();

        let layer_subresource_range = vk::ImageSubresourceRange::builder()
            .aspect_mask(vk::ImageAspectFlags::COLOR)
            .base_array_layer(layer_index as u32)
            .layer_count(1)
            .base_mip_level(0)
            .level_count(1)
            .build();

        cmd_copy_buffer_to_image(
            device_context.device(),
            upload.transfer_command_buffer(),
            upload.staging_buffer().buffer(),
            layer_offsets[*image_index],
            image.image(),
            &image.extent,
            &layer_subresource_layers,
        );

        if generate_mips {
            // Generating mipmaps includes image barriers, so this function will handle writing the
            // image barriers required to pass from the transfer queue to the dst queue
            generate_mips_for_image(
                device_context,
                upload,
                transfer_queue_family_index,
                dst_queue_family_index,
                &image,
                layer_index as u32,
                mip_level_count,
            );
        } else {
            cmd_image_memory_barrier(
                device_context.device(),
                upload.transfer_command_buffer(),
                &[image.image()],
                ImageMemoryBarrierType::PostUploadTransferQueue,
                transfer_queue_family_index,
                dst_queue_family_index,
                &layer_subresource_range,
            );

            cmd_image_memory_barrier(
                device_context.device(),
                upload.dst_command_buffer(),
                &[image.image()],
                ImageMemoryBarrierType::PostUploadDstQueue,
                transfer_queue_family_index,
                dst_queue_family_index,
                &layer_subresource_range,
            );
        }
    }

    Ok(image)
}
// This function is a little more complex to use than enqueue_load_images but can support cubemaps
// We create a layer for each layer_image_assignment, and copy from the decoded_image
// at the index matching the assignment
This function is a little more complex to use than enqueue_load_images but can support cubemaps
We create a layer for each layer_image_assignment, and copy from the decoded_image
at the index matching the assignment
This function is a little more complex to use than enqueue_load_images but can support cubemaps We create a layer for each layer_image_assignment and copy from the decoded_image at the index matching the assignment
pub fn enqueue_load_layered_image_2d(
    device_context: &VkDeviceContext,
    upload: &mut VkTransferUpload,
    transfer_queue_family_index: u32,
    dst_queue_family_index: u32,
    decoded_images: &[DecodedImage],
    layer_image_assignments: &[usize],
    create_flags: vk::ImageCreateFlags,
) -> Result<ManuallyDrop<VkImage>, VkUploadError> {
    // All images must have identical mip level count
    #[cfg(debug_assertions)]
    {
        let first = &decoded_images[0];
        for decoded_image in decoded_images {
            assert_eq!(first.mips, decoded_image.mips);
            assert_eq!(first.width, decoded_image.width);
            assert_eq!(first.height, decoded_image.height);
            assert_eq!(first.color_space, decoded_image.color_space);
            assert_eq!(first.data.len(), decoded_image.data.len());
        }
    }
    // Arbitrary, not sure if there is any requirement
    const REQUIRED_ALIGNMENT: usize = 16;
    // Check ahead of time if there is space since we are uploading multiple images
    let has_space_available = upload.has_space_available(
        decoded_images[0].data.len(),
        REQUIRED_ALIGNMENT,
        decoded_images.len(),
    );
    if !has_space_available {
        Err(VkUploadError::BufferFull)?;
    }
    let extent = vk::Extent3D {
        width: decoded_images[0].width,
        height: decoded_images[0].height,
        depth: 1,
    };
    let (mip_level_count, generate_mips) = match decoded_images[0].mips {
        DecodedImageMips::None => (1, false),
        DecodedImageMips::Precomputed(_mip_count) => unimplemented!(), //(info.mip_level_count, false),
        DecodedImageMips::Runtime(mip_count) => (mip_count, true),
    };
    // Push all images into the staging buffer
    let mut layer_offsets = Vec::default();
    for decoded_image in decoded_images {
        layer_offsets.push(upload.push(&decoded_image.data, REQUIRED_ALIGNMENT)?);
    }
    let mut image_usage = vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::SAMPLED;
    if generate_mips {
        image_usage |= vk::ImageUsageFlags::TRANSFER_SRC;
    };
    let format = match decoded_images[0].color_space {
        DecodedImageColorSpace::Linear => vk::Format::R8G8B8A8_UNORM,
        DecodedImageColorSpace::Srgb => vk::Format::R8G8B8A8_SRGB,
    };
    // Allocate an image
    let image = ManuallyDrop::new(VkImage::new(
        device_context,
        vk_mem::MemoryUsage::GpuOnly,
        create_flags,
        image_usage,
        extent,
        format,
        vk::ImageTiling::OPTIMAL,
        vk::SampleCountFlags::TYPE_1,
        layer_image_assignments.len() as u32,
        mip_level_count,
        vk::MemoryPropertyFlags::DEVICE_LOCAL,
    )?);
    //
    // Write into the transfer command buffer
    // - transition destination memory to receive the data
    // - copy the data
    // - transition the destination to the graphics queue
    //
    // Mip 0, all layers
    let subresource_range = vk::ImageSubresourceRange::builder()
        .base_array_layer(0)
        .layer_count(layer_image_assignments.len() as u32)
        .base_mip_level(0)
        .level_count(1)
        .aspect_mask(vk::ImageAspectFlags::COLOR)
        .build();
    cmd_image_memory_barrier(
        device_context.device(),
        upload.transfer_command_buffer(),
        &[image.image()],
        ImageMemoryBarrierType::PreUpload,
        transfer_queue_family_index,
        transfer_queue_family_index,
        &subresource_range,
    );
    for (layer_index, image_index) in layer_image_assignments.iter().enumerate() {
        let layer_subresource_layers = vk::ImageSubresourceLayers::builder()
            .aspect_mask(vk::ImageAspectFlags::COLOR)
            .base_array_layer(layer_index as u32)
            .layer_count(1)
            .mip_level(0)
            .build();
        let layer_subresource_range = vk::ImageSubresourceRange::builder()
            .aspect_mask(vk::ImageAspectFlags::COLOR)
            .base_array_layer(layer_index as u32)
            .layer_count(1)
            .base_mip_level(0)
            .level_count(1)
            .build();
        cmd_copy_buffer_to_image(
            device_context.device(),
            upload.transfer_command_buffer(),
            upload.staging_buffer().buffer(),
            layer_offsets[*image_index],
            image.image(),
            &image.extent,
            &layer_subresource_layers,
        );
        if generate_mips {
            // Generating mipmaps includes image barriers, so this function will handle writing the
            // image barriers required to pass from the transfer queue to the dst queue
            generate_mips_for_image(
                device_context,
                upload,
                transfer_queue_family_index,
                dst_queue_family_index,
                &image,
                layer_index as u32,
                mip_level_count,
            );
        } else {
            cmd_image_memory_barrier(
                device_context.device(),
                upload.transfer_command_buffer(),
                &[image.image()],
                ImageMemoryBarrierType::PostUploadTransferQueue,
                transfer_queue_family_index,
                dst_queue_family_index,
                &layer_subresource_range,
            );
            cmd_image_memory_barrier(
                device_context.device(),
                upload.dst_command_buffer(),
                &[image.image()],
                ImageMemoryBarrierType::PostUploadDstQueue,
                transfer_queue_family_index,
                dst_queue_family_index,
                &layer_subresource_range,
            );
        }
    }
    Ok(image)
}
pub fn enqueue_load_layered_image_2d ( device_context : & VkDeviceContext , upload : & mut VkTransferUpload , transfer_queue_family_index : u32 , dst_queue_family_index : u32 , decoded_images : & [ DecodedImage ] , layer_image_assignments : & [ usize ] , create_flags : vk :: ImageCreateFlags , ) -> Result < ManuallyDrop < VkImage > , VkUploadError > { // All images must have identical mip level count # [ cfg ( debug_assertions ) ] { let first = & decoded_images [ 0 ] ; for decoded_image in decoded_images { assert_eq ! ( first mips decoded_image mips ) ; assert_eq ! ( first width decoded_image width ) ; assert_eq ! ( first height decoded_image height ) ; assert_eq ! ( first color_space decoded_image color_space ) ; assert_eq ! ( first data len ( ) decoded_image data len ( ) ) ; } } // Arbitrary, not sure if there is any requirement const REQUIRED_ALIGNMENT : usize = 16 ; // Check ahead of time if there is space since we are uploading multiple images let has_space_available = upload . has_space_available ( decoded_images [ 0 ] . data . len ( ) , REQUIRED_ALIGNMENT , decoded_images . len ( ) , ) ; if ! has_space_available { Err ( VkUploadError :: BufferFull ) ? ; } let extent = vk :: Extent3D { width : decoded_images [ 0 ] . width , height : decoded_images [ 0 ] . height , depth : 1 , } ; let ( mip_level_count , generate_mips ) = match decoded_images [ 0 ] . mips { DecodedImageMips :: None => ( 1 , false ) , DecodedImageMips :: Precomputed ( _mip_count ) => unimplemented ! ( ) , //(info.mip_level_count, false), DecodedImageMips :: Runtime ( mip_count ) => ( mip_count , true ) , } ; // Push all images into the staging buffer let mut layer_offsets = Vec :: default ( ) ; for decoded_image in decoded_images { layer_offsets . push ( upload . push ( & decoded_image . data , REQUIRED_ALIGNMENT ) ? ) ; } let mut image_usage = vk :: ImageUsageFlags :: TRANSFER_DST | vk :: ImageUsageFlags :: SAMPLED ; if generate_mips { image_usage |= vk :: ImageUsageFlags :: TRANSFER_SRC ; } ; let format = match decoded_images [ 0 ] . color_space { DecodedImageColorSpace :: Linear => vk :: Format :: R8G8B8A8_UNORM , DecodedImageColorSpace :: Srgb => vk :: Format :: R8G8B8A8_SRGB , } ; // Allocate an image let image = ManuallyDrop :: new ( VkImage :: new ( device_context , vk_mem :: MemoryUsage :: GpuOnly , create_flags , image_usage , extent , format , vk :: ImageTiling :: OPTIMAL , vk :: SampleCountFlags :: TYPE_1 , layer_image_assignments . len ( ) as u32 , mip_level_count , vk :: MemoryPropertyFlags :: DEVICE_LOCAL , ) ? ) ; // // Write into the transfer command buffer // - transition destination memory to receive the data // - copy the data // - transition the destination to the graphics queue // // Mip 0, all layers let subresource_range = vk :: ImageSubresourceRange :: builder ( ) . base_array_layer ( 0 ) . layer_count ( layer_image_assignments . len ( ) as u32 ) . base_mip_level ( 0 ) . level_count ( 1 ) . aspect_mask ( vk :: ImageAspectFlags :: COLOR ) . build ( ) ; cmd_image_memory_barrier ( device_context . device ( ) , upload . transfer_command_buffer ( ) , & [ image . image ( ) ] , ImageMemoryBarrierType :: PreUpload , transfer_queue_family_index , transfer_queue_family_index , & subresource_range , ) ; for ( layer_index , image_index ) in layer_image_assignments . iter ( ) . enumerate ( ) { let layer_subresource_layers = vk :: ImageSubresourceLayers :: builder ( ) . aspect_mask ( vk :: ImageAspectFlags :: COLOR ) . base_array_layer ( layer_index as u32 ) . layer_count ( 1 ) . mip_level ( 0 ) . build ( ) ; let layer_subresource_range = vk :: ImageSubresourceRange :: builder ( ) . aspect_mask ( vk :: ImageAspectFlags :: COLOR ) . base_array_layer ( layer_index as u32 ) . layer_count ( 1 ) . base_mip_level ( 0 ) . level_count ( 1 ) . build ( ) ; cmd_copy_buffer_to_image ( device_context . device ( ) , upload . transfer_command_buffer ( ) , upload . staging_buffer ( ) . buffer ( ) , layer_offsets [ * image_index ] , image . image ( ) , & image . extent , & layer_subresource_layers , ) ; if generate_mips { // Generating mipmaps includes image barriers, so this function will handle writing the // image barriers required to pass from the transfer queue to the dst queue generate_mips_for_image ( device_context , upload , transfer_queue_family_index , dst_queue_family_index , & image , layer_index as u32 , mip_level_count , ) ; } else { cmd_image_memory_barrier ( device_context . device ( ) , upload . transfer_command_buffer ( ) , & [ image . image ( ) ] , ImageMemoryBarrierType :: PostUploadTransferQueue , transfer_queue_family_index , dst_queue_family_index , & layer_subresource_range , ) ; cmd_image_memory_barrier ( device_context . device ( ) , upload . dst_command_buffer ( ) , & [ image . image ( ) ] , ImageMemoryBarrierType :: PostUploadDstQueue , transfer_queue_family_index , dst_queue_family_index , & layer_subresource_range , ) ; } } Ok ( image ) }
This function is a little more complex to use than enqueue_load_images but can support cubemaps
We create a layer for each layer_image_assignment, and copy from the decoded_image
at the index matching the assignment
This function is a little more complex to use than enqueue_load_images but can support cubemaps We create a layer for each layer_image_assignment and copy from the decoded_image at the index matching the assignment
device_context
&VkDeviceContext
upload
&mut VkTransferUpload
transfer_queue_family_index
u32
dst_queue_family_index
u32
decoded_images
&[DecodedImage]
layer_image_assignments
&[usize]
create_flags
vk::ImageCreateFlags
device_context
&VkDeviceContext
upload
&mut VkTransferUpload
transfer_queue_family_index
u32
dst_queue_family_index
u32
decoded_images
&[DecodedImage]
layer_image_assignments
&[usize]
create_flags
vk::ImageCreateFlags