From 5e485438823eb1922d6bf1dce82f2716f6c74047 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 10 Sep 2022 12:24:29 +0200 Subject: [PATCH] Add sparse image querying functions --- vulkano/src/command_buffer/auto.rs | 2 +- vulkano/src/device/mod.rs | 82 ++++++ vulkano/src/device/physical.rs | 400 +++++++++++++++-------------- vulkano/src/image/mod.rs | 134 ++++++++++ vulkano/src/image/sys.rs | 186 +++++++++++++- vulkano/src/memory/mod.rs | 113 +++++++- vulkano/src/memory/pool/mod.rs | 3 +- 7 files changed, 723 insertions(+), 197 deletions(-) diff --git a/vulkano/src/command_buffer/auto.rs b/vulkano/src/command_buffer/auto.rs index 6dc279d2a3..2d2ca3ca09 100644 --- a/vulkano/src/command_buffer/auto.rs +++ b/vulkano/src/command_buffer/auto.rs @@ -21,7 +21,7 @@ use super::{ use crate::{ buffer::{sys::UnsafeBuffer, BufferAccess}, command_buffer::CommandBufferInheritanceRenderingInfo, - device::{physical::QueueFamilyProperties, Device, DeviceOwned, Queue}, + device::{Device, DeviceOwned, Queue, QueueFamilyProperties}, format::Format, image::{sys::UnsafeImage, ImageAccess, ImageLayout, ImageSubresourceRange}, query::{QueryControlFlags, QueryType}, diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 5daed4b7e2..fff5c5884b 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -111,7 +111,9 @@ use crate::{ command_buffer::pool::StandardCommandPool, descriptor_set::pool::StandardDescriptorPool, instance::{debug::DebugUtilsLabel, Instance}, + macros::vulkan_bitflags, memory::{pool::StandardMemoryPool, ExternalMemoryHandleType}, + sync::PipelineStage, OomError, RequirementNotMet, RequiresOneOf, SynchronizedVulkanObject, Version, VulkanError, VulkanObject, }; @@ -1247,6 +1249,86 @@ impl Hash for Queue { } } +/// Properties of a queue family in a physical device. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct QueueFamilyProperties { + /// Attributes of the queue family. + pub queue_flags: QueueFlags, + + /// The number of queues available in this family. + /// + /// This guaranteed to be at least 1 (or else that family wouldn't exist). + pub queue_count: u32, + + /// If timestamps are supported, the number of bits supported by timestamp operations. + /// The returned value will be in the range 36..64. + /// + /// If timestamps are not supported, this is `None`. + pub timestamp_valid_bits: Option, + + /// The minimum granularity supported for image transfers, in terms of `[width, height, depth]`. + pub min_image_transfer_granularity: [u32; 3], +} + +impl QueueFamilyProperties { + /// Returns whether the queues of this family support a particular pipeline stage. + #[inline] + pub fn supports_stage(&self, stage: PipelineStage) -> bool { + ash::vk::QueueFlags::from(self.queue_flags).contains(stage.required_queue_flags()) + } +} + +impl From for QueueFamilyProperties { + #[inline] + fn from(val: ash::vk::QueueFamilyProperties) -> Self { + Self { + queue_flags: val.queue_flags.into(), + queue_count: val.queue_count, + timestamp_valid_bits: (val.timestamp_valid_bits != 0) + .then_some(val.timestamp_valid_bits), + min_image_transfer_granularity: [ + val.min_image_transfer_granularity.width, + val.min_image_transfer_granularity.height, + val.min_image_transfer_granularity.depth, + ], + } + } +} + +vulkan_bitflags! { + /// Attributes of a queue or queue family. + #[non_exhaustive] + QueueFlags = QueueFlags(u32); + + /// Queues of this family can execute graphics operations. + graphics = GRAPHICS, + + /// Queues of this family can execute compute operations. + compute = COMPUTE, + + /// Queues of this family can execute transfer operations. + transfer = TRANSFER, + + /// Queues of this family can execute sparse memory management operations. + sparse_binding = SPARSE_BINDING, + + /// Queues of this family can be created using the `protected` flag. + protected = PROTECTED { + api_version: V1_1, + }, + + /// Queues of this family can execute video decode operations. + video_decode = VIDEO_DECODE_KHR { + device_extensions: [khr_video_decode_queue], + }, + + /// Queues of this family can execute video encode operations. + video_encode = VIDEO_ENCODE_KHR { + device_extensions: [khr_video_encode_queue], + }, +} + /// Error that can happen when submitting a debug utils command to a queue. #[derive(Clone, Debug)] pub enum DebugUtilsError { diff --git a/vulkano/src/device/physical.rs b/vulkano/src/device/physical.rs index 30fae88586..accd51b505 100644 --- a/vulkano/src/device/physical.rs +++ b/vulkano/src/device/physical.rs @@ -7,19 +7,24 @@ // notice may not be copied, modified, or distributed except // according to those terms. +use super::QueueFamilyProperties; use crate::{ buffer::{ExternalBufferInfo, ExternalBufferProperties}, device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi}, format::{Format, FormatProperties}, - image::{ImageCreateFlags, ImageFormatInfo, ImageFormatProperties, ImageUsage}, + image::{ + ImageCreateFlags, ImageFormatInfo, ImageFormatProperties, ImageUsage, + SparseImageFormatInfo, SparseImageFormatProperties, + }, instance::Instance, macros::{vulkan_bitflags, vulkan_enum}, + memory::MemoryProperties, swapchain::{ ColorSpace, FullScreenExclusive, PresentMode, SupportedSurfaceTransforms, Surface, SurfaceApi, SurfaceCapabilities, SurfaceInfo, }, - sync::{ExternalSemaphoreInfo, ExternalSemaphoreProperties, PipelineStage}, - DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, + sync::{ExternalSemaphoreInfo, ExternalSemaphoreProperties}, + OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, }; use bytemuck::cast_slice; use std::{ @@ -722,6 +727,9 @@ impl PhysicalDevice { // VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter usage.validate_physical_device(self)?; + // VUID-VkPhysicalDeviceImageFormatInfo2-usage-requiredbitmask + assert!(!usage.is_empty()); + if let Some(handle_type) = external_memory_handle_type { if !(self.api_version() >= Version::V1_1 || self @@ -901,6 +909,203 @@ impl PhysicalDevice { } } + /// Returns the properties of sparse images with a given image configuration. + /// + /// # Panics + /// + /// - Panics if `format_info.format` is `None`. + #[inline] + pub fn sparse_image_format_properties( + &self, + format_info: SparseImageFormatInfo, + ) -> Result, ImageFormatPropertiesError> { + self.validate_sparse_image_format_properties(&format_info)?; + + unsafe { Ok(self.sparse_image_format_properties_unchecked(format_info)) } + } + + fn validate_sparse_image_format_properties( + &self, + format_info: &SparseImageFormatInfo, + ) -> Result<(), ImageFormatPropertiesError> { + let &SparseImageFormatInfo { + format: _, + image_type, + samples, + usage, + tiling, + _ne: _, + } = format_info; + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-format-parameter + // TODO: format.validate_physical_device(self)?; + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-type-parameter + image_type.validate_physical_device(self)?; + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-samples-parameter + samples.validate_physical_device(self)?; + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-usage-parameter + usage.validate_physical_device(self)?; + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-usage-requiredbitmask + assert!(!usage.is_empty()); + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-tiling-parameter + tiling.validate_physical_device(self)?; + + // VUID-VkPhysicalDeviceSparseImageFormatInfo2-samples-01095 + // TODO: + + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub unsafe fn sparse_image_format_properties_unchecked( + &self, + format_info: SparseImageFormatInfo, + ) -> Vec { + let SparseImageFormatInfo { + format, + image_type, + samples, + usage, + tiling, + _ne: _, + } = format_info; + + let format_info2 = ash::vk::PhysicalDeviceSparseImageFormatInfo2 { + format: format.unwrap().into(), + ty: image_type.into(), + samples: samples.into(), + usage: usage.into(), + tiling: tiling.into(), + ..Default::default() + }; + + let fns = self.instance.fns(); + + if self.api_version() >= Version::V1_1 + || self + .instance + .enabled_extensions() + .khr_get_physical_device_properties2 + { + let mut count = 0; + + if self.api_version() >= Version::V1_1 { + (fns.v1_1.get_physical_device_sparse_image_format_properties2)( + self.handle, + &format_info2, + &mut count, + ptr::null_mut(), + ); + } else { + (fns.khr_get_physical_device_properties2 + .get_physical_device_sparse_image_format_properties2_khr)( + self.handle, + &format_info2, + &mut count, + ptr::null_mut(), + ); + } + + let mut sparse_image_format_properties2 = + vec![ash::vk::SparseImageFormatProperties2::default(); count as usize]; + + if self.api_version() >= Version::V1_1 { + (fns.v1_1.get_physical_device_sparse_image_format_properties2)( + self.handle, + &format_info2, + &mut count, + sparse_image_format_properties2.as_mut_ptr(), + ); + } else { + (fns.khr_get_physical_device_properties2 + .get_physical_device_sparse_image_format_properties2_khr)( + self.handle, + &format_info2, + &mut count, + sparse_image_format_properties2.as_mut_ptr(), + ); + } + + sparse_image_format_properties2.set_len(count as usize); + + sparse_image_format_properties2 + .into_iter() + .map( + |sparse_image_format_properties2| SparseImageFormatProperties { + aspects: sparse_image_format_properties2 + .properties + .aspect_mask + .into(), + image_granularity: [ + sparse_image_format_properties2 + .properties + .image_granularity + .width, + sparse_image_format_properties2 + .properties + .image_granularity + .height, + sparse_image_format_properties2 + .properties + .image_granularity + .depth, + ], + flags: sparse_image_format_properties2.properties.flags.into(), + }, + ) + .collect() + } else { + let mut count = 0; + + (fns.v1_0.get_physical_device_sparse_image_format_properties)( + self.handle, + format_info2.format, + format_info2.ty, + format_info2.samples, + format_info2.usage, + format_info2.tiling, + &mut count, + ptr::null_mut(), + ); + + let mut sparse_image_format_properties = + vec![ash::vk::SparseImageFormatProperties::default(); count as usize]; + + (fns.v1_0.get_physical_device_sparse_image_format_properties)( + self.handle, + format_info2.format, + format_info2.ty, + format_info2.samples, + format_info2.usage, + format_info2.tiling, + &mut count, + sparse_image_format_properties.as_mut_ptr(), + ); + + sparse_image_format_properties.set_len(count as usize); + + sparse_image_format_properties + .into_iter() + .map( + |sparse_image_format_properties| SparseImageFormatProperties { + aspects: sparse_image_format_properties.aspect_mask.into(), + image_granularity: [ + sparse_image_format_properties.image_granularity.width, + sparse_image_format_properties.image_granularity.height, + sparse_image_format_properties.image_granularity.depth, + ], + flags: sparse_image_format_properties.flags.into(), + }, + ) + .collect() + } + } + /// Returns the capabilities that are supported by the physical device for the given surface. /// /// # Panic @@ -1499,195 +1704,6 @@ impl From for ExtensionProperties { } } -/// Properties of the memory in a physical device. -#[derive(Clone, Debug)] -#[non_exhaustive] -pub struct MemoryProperties { - /// The available memory types. - pub memory_types: Vec, - - /// The available memory heaps. - pub memory_heaps: Vec, -} - -impl From for MemoryProperties { - #[inline] - fn from(val: ash::vk::PhysicalDeviceMemoryProperties) -> Self { - Self { - memory_types: val.memory_types[0..val.memory_type_count as usize] - .iter() - .map(|vk_memory_type| MemoryType { - property_flags: vk_memory_type.property_flags.into(), - heap_index: vk_memory_type.heap_index, - }) - .collect(), - memory_heaps: val.memory_heaps[0..val.memory_heap_count as usize] - .iter() - .map(|vk_memory_heap| MemoryHeap { - size: vk_memory_heap.size, - flags: vk_memory_heap.flags.into(), - }) - .collect(), - } - } -} - -/// A memory type in a physical device. -#[derive(Clone, Debug)] -#[non_exhaustive] -pub struct MemoryType { - /// The properties of this memory type. - pub property_flags: MemoryPropertyFlags, - - /// The index of the memory heap that this memory type corresponds to. - pub heap_index: u32, -} - -vulkan_bitflags! { - /// Properties of a memory type. - #[non_exhaustive] - MemoryPropertyFlags = MemoryPropertyFlags(u32); - - /// The memory is located on the device. This usually means that it's efficient for the - /// device to access this memory. - device_local = DEVICE_LOCAL, - - /// The memory can be accessed by the host. - host_visible = HOST_VISIBLE, - - /// Modifications made by the host or the device on this memory type are - /// instantaneously visible to the other party. If memory does not have this flag, changes to - /// the memory are not visible until they are flushed or invalidated. - host_coherent = HOST_COHERENT, - - /// The memory is cached by the host. Host memory accesses to cached memory are faster than for - /// uncached memory, but the cache may not be coherent. - host_cached = HOST_CACHED, - - /// Allocations made from this memory type are lazy. - /// - /// This means that no actual allocation is performed. Instead memory is automatically - /// allocated by the Vulkan implementation based on need. - /// - /// Memory of this type can only be used on images created with a certain flag. Memory of this - /// type is never host-visible. - lazily_allocated = LAZILY_ALLOCATED, - - /// The memory can only be accessed by the device, and allows protected queue access. - /// - /// Memory of this type is never host visible, host coherent or host cached. - protected = PROTECTED { - api_version: V1_1, - }, -} - -/// A memory heap in a physical device. -#[derive(Clone, Debug)] -#[non_exhaustive] -pub struct MemoryHeap { - /// The size of the heap in bytes. - pub size: DeviceSize, - - /// Attributes of the heap. - pub flags: MemoryHeapFlags, -} - -vulkan_bitflags! { - /// Attributes of a memory heap. - #[non_exhaustive] - MemoryHeapFlags = MemoryHeapFlags(u32); - - /// The heap corresponds to device-local memory. - device_local = DEVICE_LOCAL, - - /// If used on a logical device that represents more than one physical device, allocations are - /// replicated across each physical device's instance of this heap. - multi_instance = MULTI_INSTANCE { - api_version: V1_1, - instance_extensions: [khr_device_group_creation], - }, -} - -/// Properties of a queue family in a physical device. -#[derive(Clone, Debug)] -#[non_exhaustive] -pub struct QueueFamilyProperties { - /// Attributes of the queue family. - pub queue_flags: QueueFlags, - - /// The number of queues available in this family. - /// - /// This guaranteed to be at least 1 (or else that family wouldn't exist). - pub queue_count: u32, - - /// If timestamps are supported, the number of bits supported by timestamp operations. - /// The returned value will be in the range 36..64. - /// - /// If timestamps are not supported, this is `None`. - pub timestamp_valid_bits: Option, - - /// The minimum granularity supported for image transfers, in terms of `[width, height, depth]`. - pub min_image_transfer_granularity: [u32; 3], -} - -impl QueueFamilyProperties { - /// Returns whether the queues of this family support a particular pipeline stage. - #[inline] - pub fn supports_stage(&self, stage: PipelineStage) -> bool { - ash::vk::QueueFlags::from(self.queue_flags).contains(stage.required_queue_flags()) - } -} - -impl From for QueueFamilyProperties { - #[inline] - fn from(val: ash::vk::QueueFamilyProperties) -> Self { - Self { - queue_flags: val.queue_flags.into(), - queue_count: val.queue_count, - timestamp_valid_bits: (val.timestamp_valid_bits != 0) - .then_some(val.timestamp_valid_bits), - min_image_transfer_granularity: [ - val.min_image_transfer_granularity.width, - val.min_image_transfer_granularity.height, - val.min_image_transfer_granularity.depth, - ], - } - } -} - -vulkan_bitflags! { - /// Attributes of a queue or queue family. - #[non_exhaustive] - QueueFlags = QueueFlags(u32); - - /// Queues of this family can execute graphics operations. - graphics = GRAPHICS, - - /// Queues of this family can execute compute operations. - compute = COMPUTE, - - /// Queues of this family can execute transfer operations. - transfer = TRANSFER, - - /// Queues of this family can execute sparse memory management operations. - sparse_binding = SPARSE_BINDING, - - /// Queues of this family can be created using the `protected` flag. - protected = PROTECTED { - api_version: V1_1, - }, - - /// Queues of this family can execute video decode operations. - video_decode = VIDEO_DECODE_KHR { - device_extensions: [khr_video_decode_queue], - }, - - /// Queues of this family can execute video encode operations. - video_encode = VIDEO_ENCODE_KHR { - device_extensions: [khr_video_encode_queue], - }, -} - vulkan_enum! { /// Type of a physical device. #[non_exhaustive] diff --git a/vulkano/src/image/mod.rs b/vulkano/src/image/mod.rs index a514d0752d..6909e5b688 100644 --- a/vulkano/src/image/mod.rs +++ b/vulkano/src/image/mod.rs @@ -574,6 +574,35 @@ impl From for ImageSubresourceRange { } } +/// Describes the memory layout of an image. +/// +/// The address of a texel at `(x, y, z, layer)` is `layer * array_pitch + z * depth_pitch + +/// y * row_pitch + x * size_of_each_texel + offset`. `size_of_each_texel` must be determined +/// depending on the format. The same formula applies for compressed formats, except that the +/// coordinates must be in number of blocks. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SubresourceLayout { + /// The number of bytes from the start of the memory where the subresource begins. + pub offset: DeviceSize, + + /// The size in bytes in the subresource. It includes any extra memory that is required based on + /// `row_pitch`. + pub size: DeviceSize, + + /// The number of bytes between adjacent rows of texels. + pub row_pitch: DeviceSize, + + /// The number of bytes between adjacent array layers. + /// + /// This value is undefined for images with only one array layer. + pub array_pitch: DeviceSize, + + /// The number of bytes between adjacent depth slices. + /// + /// This value is undefined for images that are not three-dimensional. + pub depth_pitch: DeviceSize, +} + /// The image configuration to query in /// [`PhysicalDevice::image_format_properties`](crate::device::physical::PhysicalDevice::image_format_properties). #[derive(Clone, Debug)] @@ -698,6 +727,7 @@ pub struct ImageFormatProperties { } impl From for ImageFormatProperties { + #[inline] fn from(props: ash::vk::ImageFormatProperties) -> Self { Self { max_extent: [ @@ -716,6 +746,110 @@ impl From for ImageFormatProperties { } } +/// The image configuration to query in +/// [`PhysicalDevice::sparse_image_format_properties`](crate::device::physical::PhysicalDevice::sparse_image_format_properties). +#[derive(Clone, Debug)] +pub struct SparseImageFormatInfo { + /// The `format` that the image will have. + /// + /// The default value is `None`, which must be overridden. + pub format: Option, + + /// The dimension type that the image will have. + /// + /// The default value is [`ImageType::Dim2d`]. + pub image_type: ImageType, + + /// The `samples` that the image will have. + /// + /// The default value is `SampleCount::Sample1`. + pub samples: SampleCount, + + /// The `usage` that the image will have. + /// + /// The default value is [`ImageUsage::empty()`], which must be overridden. + pub usage: ImageUsage, + + /// The `tiling` that the image will have. + /// + /// The default value is [`ImageTiling::Optimal`]. + pub tiling: ImageTiling, + + pub _ne: crate::NonExhaustive, +} + +impl Default for SparseImageFormatInfo { + #[inline] + fn default() -> Self { + Self { + format: None, + image_type: ImageType::Dim2d, + samples: SampleCount::Sample1, + usage: ImageUsage::empty(), + tiling: ImageTiling::Optimal, + _ne: crate::NonExhaustive(()), + } + } +} + +/// The properties that are supported by a physical device for sparse images of a certain type. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct SparseImageFormatProperties { + /// The aspects of the image that the properties apply to. + pub aspects: ImageAspects, + + /// The size of the sparse image block, in texels or compressed texel blocks. + /// + /// If `flags.nonstandard_block_size` is set, then these values do not match the standard + /// sparse block dimensions for the given format. + pub image_granularity: [u32; 3], + + /// Additional information about the sparse image. + pub flags: SparseImageFormatFlags, +} + +vulkan_bitflags! { + /// Flags specifying information about a sparse resource. + SparseImageFormatFlags = SparseImageFormatFlags(u32); + + /// The image uses a single mip tail region for all array layers, instead of one mip tail region + /// per array layer. + single_miptail = SINGLE_MIPTAIL, + + /// The image's mip tail region begins with the first mip level whose dimensions are not an + /// integer multiple of the corresponding sparse image block dimensions. + aligned_mip_size = ALIGNED_MIP_SIZE, + + /// The image uses non-standard sparse image block dimensions. + nonstandard_block_size = NONSTANDARD_BLOCK_SIZE, +} + +/// Requirements for binding memory to a sparse image. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct SparseImageMemoryRequirements { + /// The properties of the image format. + pub format_properties: SparseImageFormatProperties, + + /// The first mip level at which image subresources are included in the mip tail region. + pub image_mip_tail_first_lod: u32, + + /// The size in bytes of the mip tail region. This value is guaranteed to be a multiple of the + /// sparse block size in bytes. + /// + /// If `format_properties.flags.single_miptail` is set, then this is the size of the whole + /// mip tail. Otherwise it is the size of the mip tail of a single array layer. + pub image_mip_tail_size: DeviceSize, + + /// The memory offset that must be used to bind the mip tail region. + pub image_mip_tail_offset: DeviceSize, + + /// If `format_properties.flags.single_miptail` is not set, specifies the stride between + /// the mip tail regions of each array layer. + pub image_mip_tail_stride: Option, +} + #[cfg(test)] mod tests { use crate::{ diff --git a/vulkano/src/image/sys.rs b/vulkano/src/image/sys.rs index dbd3b84102..7e4a853d7f 100644 --- a/vulkano/src/image/sys.rs +++ b/vulkano/src/image/sys.rs @@ -16,13 +16,16 @@ use super::{ ImageAspect, ImageAspects, ImageCreateFlags, ImageDimensions, ImageLayout, ImageSubresourceLayers, ImageSubresourceRange, ImageTiling, ImageUsage, SampleCount, - SampleCounts, + SampleCounts, SparseImageMemoryRequirements, }; use crate::{ buffer::cpu_access::{ReadLockError, WriteLockError}, device::{physical::ImageFormatPropertiesError, Device, DeviceOwned}, format::{ChromaSampling, Format, FormatFeatures, NumericType}, - image::{view::ImageViewCreationError, ImageFormatInfo, ImageFormatProperties, ImageType}, + image::{ + view::ImageViewCreationError, ImageFormatInfo, ImageFormatProperties, ImageType, + SparseImageFormatProperties, + }, memory::{ DeviceMemory, DeviceMemoryAllocationError, ExternalMemoryHandleType, ExternalMemoryHandleTypes, MemoryRequirements, @@ -1011,6 +1014,185 @@ impl UnsafeImage { } } + /// Returns the sparse memory requirements for this image. + pub fn sparse_memory_requirements(&self) -> Vec { + let device = &self.device; + + unsafe { + let fns = self.device.fns(); + + if device.api_version() >= Version::V1_1 + || device.enabled_extensions().khr_get_memory_requirements2 + { + let info2 = ash::vk::ImageSparseMemoryRequirementsInfo2 { + image: self.handle, + ..Default::default() + }; + + let mut count = 0; + + if device.api_version() >= Version::V1_1 { + (fns.v1_1.get_image_sparse_memory_requirements2)( + device.internal_object(), + &info2, + &mut count, + ptr::null_mut(), + ); + } else { + (fns.khr_get_memory_requirements2 + .get_image_sparse_memory_requirements2_khr)( + device.internal_object(), + &info2, + &mut count, + ptr::null_mut(), + ); + } + + let mut sparse_image_memory_requirements2 = + vec![ash::vk::SparseImageMemoryRequirements2::default(); count as usize]; + + if device.api_version() >= Version::V1_1 { + (fns.v1_1.get_image_sparse_memory_requirements2)( + self.device.internal_object(), + &info2, + &mut count, + sparse_image_memory_requirements2.as_mut_ptr(), + ); + } else { + (fns.khr_get_memory_requirements2 + .get_image_sparse_memory_requirements2_khr)( + self.device.internal_object(), + &info2, + &mut count, + sparse_image_memory_requirements2.as_mut_ptr(), + ); + } + + sparse_image_memory_requirements2.set_len(count as usize); + + sparse_image_memory_requirements2 + .into_iter() + .map( + |sparse_image_memory_requirements2| SparseImageMemoryRequirements { + format_properties: SparseImageFormatProperties { + aspects: sparse_image_memory_requirements2 + .memory_requirements + .format_properties + .aspect_mask + .into(), + image_granularity: [ + sparse_image_memory_requirements2 + .memory_requirements + .format_properties + .image_granularity + .width, + sparse_image_memory_requirements2 + .memory_requirements + .format_properties + .image_granularity + .height, + sparse_image_memory_requirements2 + .memory_requirements + .format_properties + .image_granularity + .depth, + ], + flags: sparse_image_memory_requirements2 + .memory_requirements + .format_properties + .flags + .into(), + }, + image_mip_tail_first_lod: sparse_image_memory_requirements2 + .memory_requirements + .image_mip_tail_first_lod, + image_mip_tail_size: sparse_image_memory_requirements2 + .memory_requirements + .image_mip_tail_size, + image_mip_tail_offset: sparse_image_memory_requirements2 + .memory_requirements + .image_mip_tail_offset, + image_mip_tail_stride: (!sparse_image_memory_requirements2 + .memory_requirements + .format_properties + .flags + .intersects(ash::vk::SparseImageFormatFlags::SINGLE_MIPTAIL)) + .then_some( + sparse_image_memory_requirements2 + .memory_requirements + .image_mip_tail_stride, + ), + }, + ) + .collect() + } else { + let mut count = 0; + + (fns.v1_0.get_image_sparse_memory_requirements)( + device.internal_object(), + self.handle, + &mut count, + ptr::null_mut(), + ); + + let mut sparse_image_memory_requirements = + vec![ash::vk::SparseImageMemoryRequirements::default(); count as usize]; + + (fns.v1_0.get_image_sparse_memory_requirements)( + device.internal_object(), + self.handle, + &mut count, + sparse_image_memory_requirements.as_mut_ptr(), + ); + + sparse_image_memory_requirements.set_len(count as usize); + + sparse_image_memory_requirements + .into_iter() + .map( + |sparse_image_memory_requirements| SparseImageMemoryRequirements { + format_properties: SparseImageFormatProperties { + aspects: sparse_image_memory_requirements + .format_properties + .aspect_mask + .into(), + image_granularity: [ + sparse_image_memory_requirements + .format_properties + .image_granularity + .width, + sparse_image_memory_requirements + .format_properties + .image_granularity + .height, + sparse_image_memory_requirements + .format_properties + .image_granularity + .depth, + ], + flags: sparse_image_memory_requirements + .format_properties + .flags + .into(), + }, + image_mip_tail_first_lod: sparse_image_memory_requirements + .image_mip_tail_first_lod, + image_mip_tail_size: sparse_image_memory_requirements + .image_mip_tail_size, + image_mip_tail_offset: sparse_image_memory_requirements + .image_mip_tail_offset, + image_mip_tail_stride: (!sparse_image_memory_requirements + .format_properties + .flags + .intersects(ash::vk::SparseImageFormatFlags::SINGLE_MIPTAIL)) + .then_some(sparse_image_memory_requirements.image_mip_tail_stride), + }, + ) + .collect() + } + } + } + pub unsafe fn bind_memory( &self, memory: &DeviceMemory, diff --git a/vulkano/src/memory/mod.rs b/vulkano/src/memory/mod.rs index c3e00fbd08..ff2fb4b1f7 100644 --- a/vulkano/src/memory/mod.rs +++ b/vulkano/src/memory/mod.rs @@ -100,11 +100,122 @@ pub use self::{ }, pool::MemoryPool, }; -use crate::{buffer::sys::UnsafeBuffer, image::sys::UnsafeImage, DeviceSize}; +use crate::{ + buffer::sys::UnsafeBuffer, image::sys::UnsafeImage, macros::vulkan_bitflags, DeviceSize, +}; mod device_memory; pub mod pool; +/// Properties of the memory in a physical device. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct MemoryProperties { + /// The available memory types. + pub memory_types: Vec, + + /// The available memory heaps. + pub memory_heaps: Vec, +} + +impl From for MemoryProperties { + #[inline] + fn from(val: ash::vk::PhysicalDeviceMemoryProperties) -> Self { + Self { + memory_types: val.memory_types[0..val.memory_type_count as usize] + .iter() + .map(|vk_memory_type| MemoryType { + property_flags: vk_memory_type.property_flags.into(), + heap_index: vk_memory_type.heap_index, + }) + .collect(), + memory_heaps: val.memory_heaps[0..val.memory_heap_count as usize] + .iter() + .map(|vk_memory_heap| MemoryHeap { + size: vk_memory_heap.size, + flags: vk_memory_heap.flags.into(), + }) + .collect(), + } + } +} + +/// A memory type in a physical device. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct MemoryType { + /// The properties of this memory type. + pub property_flags: MemoryPropertyFlags, + + /// The index of the memory heap that this memory type corresponds to. + pub heap_index: u32, +} + +vulkan_bitflags! { + /// Properties of a memory type. + #[non_exhaustive] + MemoryPropertyFlags = MemoryPropertyFlags(u32); + + /// The memory is located on the device. This usually means that it's efficient for the + /// device to access this memory. + device_local = DEVICE_LOCAL, + + /// The memory can be accessed by the host. + host_visible = HOST_VISIBLE, + + /// Modifications made by the host or the device on this memory type are + /// instantaneously visible to the other party. If memory does not have this flag, changes to + /// the memory are not visible until they are flushed or invalidated. + host_coherent = HOST_COHERENT, + + /// The memory is cached by the host. Host memory accesses to cached memory are faster than for + /// uncached memory, but the cache may not be coherent. + host_cached = HOST_CACHED, + + /// Allocations made from this memory type are lazy. + /// + /// This means that no actual allocation is performed. Instead memory is automatically + /// allocated by the Vulkan implementation based on need. + /// + /// Memory of this type can only be used on images created with a certain flag. Memory of this + /// type is never host-visible. + lazily_allocated = LAZILY_ALLOCATED, + + /// The memory can only be accessed by the device, and allows protected queue access. + /// + /// Memory of this type is never host visible, host coherent or host cached. + protected = PROTECTED { + api_version: V1_1, + }, +} + +/// A memory heap in a physical device. +#[derive(Clone, Debug)] +#[non_exhaustive] +pub struct MemoryHeap { + /// The size of the heap in bytes. + pub size: DeviceSize, + + /// Attributes of the heap. + pub flags: MemoryHeapFlags, +} + +vulkan_bitflags! { + /// Attributes of a memory heap. + #[non_exhaustive] + MemoryHeapFlags = MemoryHeapFlags(u32); + + /// The heap corresponds to device-local memory. + device_local = DEVICE_LOCAL, + + /// If used on a logical device that represents more than one physical device, allocations are + /// replicated across each physical device's instance of this heap. + multi_instance = MULTI_INSTANCE { + api_version: V1_1, + instance_extensions: [khr_device_group_creation], + }, +} + /// Represents requirements expressed by the Vulkan implementation when it comes to binding memory /// to a resource. #[derive(Debug, Copy, Clone)] diff --git a/vulkano/src/memory/pool/mod.rs b/vulkano/src/memory/pool/mod.rs index 2155f87e29..4f39a6ce37 100644 --- a/vulkano/src/memory/pool/mod.rs +++ b/vulkano/src/memory/pool/mod.rs @@ -14,8 +14,9 @@ pub use self::{ }, pool::{StandardMemoryPool, StandardMemoryPoolAlloc}, }; +use super::MemoryType; use crate::{ - device::{physical::MemoryType, Device, DeviceOwned}, + device::{Device, DeviceOwned}, memory::{ device_memory::MemoryAllocateInfo, DedicatedAllocation, DeviceMemory, DeviceMemoryAllocationError, ExternalMemoryHandleTypes, MappedDeviceMemory,