mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
Add support for image format lists (#2287)
* Add support for image format lists * Not "additional" formats
This commit is contained in:
parent
b3ef5d746b
commit
d47f45c478
@ -1029,6 +1029,7 @@ impl PhysicalDevice {
|
||||
external_memory_handle_type,
|
||||
image_view_type,
|
||||
ref drm_format_modifier_info,
|
||||
ref view_formats,
|
||||
_ne: _,
|
||||
} = image_format_info;
|
||||
|
||||
@ -1042,6 +1043,8 @@ impl PhysicalDevice {
|
||||
};
|
||||
let mut drm_format_modifier_info_vk = None;
|
||||
let mut external_info_vk = None;
|
||||
let mut format_list_info_vk = None;
|
||||
let format_list_view_formats_vk: Vec<_>;
|
||||
let mut image_view_info_vk = None;
|
||||
let mut stencil_usage_info_vk = None;
|
||||
|
||||
@ -1087,6 +1090,23 @@ impl PhysicalDevice {
|
||||
info2_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if !view_formats.is_empty() {
|
||||
format_list_view_formats_vk = view_formats
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ash::vk::Format::from)
|
||||
.collect();
|
||||
|
||||
let next = format_list_info_vk.insert(ash::vk::ImageFormatListCreateInfo {
|
||||
view_format_count: format_list_view_formats_vk.len() as u32,
|
||||
p_view_formats: format_list_view_formats_vk.as_ptr(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = info2_vk.p_next;
|
||||
info2_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if let Some(image_view_type) = image_view_type {
|
||||
let next = image_view_info_vk.insert(
|
||||
ash::vk::PhysicalDeviceImageViewImageFormatInfoEXT {
|
||||
|
@ -207,10 +207,12 @@ impl Image {
|
||||
swapchain: Arc<Swapchain>,
|
||||
image_index: u32,
|
||||
) -> Result<Self, VulkanError> {
|
||||
// Per https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkCreateSwapchainKHR.html#_description
|
||||
let create_info = ImageCreateInfo {
|
||||
flags: ImageCreateFlags::empty(),
|
||||
flags: swapchain.flags().into(),
|
||||
image_type: ImageType::Dim2d,
|
||||
format: swapchain.image_format(),
|
||||
view_formats: swapchain.image_view_formats().to_vec(),
|
||||
extent: [swapchain.image_extent()[0], swapchain.image_extent()[1], 1],
|
||||
array_layers: swapchain.image_array_layers(),
|
||||
mip_levels: 1,
|
||||
@ -220,7 +222,10 @@ impl Image {
|
||||
stencil_usage: None,
|
||||
sharing: swapchain.image_sharing().clone(),
|
||||
initial_layout: ImageLayout::Undefined,
|
||||
..Default::default()
|
||||
drm_format_modifiers: Vec::new(),
|
||||
drm_format_modifier_plane_layouts: Vec::new(),
|
||||
external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
};
|
||||
|
||||
Ok(Self::from_raw(
|
||||
@ -279,6 +284,12 @@ impl Image {
|
||||
self.inner.format_features()
|
||||
}
|
||||
|
||||
/// Returns the formats that an image view created from this image can have.
|
||||
#[inline]
|
||||
pub fn view_formats(&self) -> &[Format] {
|
||||
self.inner.view_formats()
|
||||
}
|
||||
|
||||
/// Returns the extent of the image.
|
||||
#[inline]
|
||||
pub fn extent(&self) -> [u32; 3] {
|
||||
@ -971,7 +982,7 @@ impl FusedIterator for SubresourceRangeIterator {}
|
||||
vulkan_bitflags! {
|
||||
#[non_exhaustive]
|
||||
|
||||
/// Flags that can be set when creating a new image.
|
||||
/// Flags specifying additional properties of an image.
|
||||
ImageCreateFlags = ImageCreateFlags(u32);
|
||||
|
||||
/* TODO: enable
|
||||
@ -1647,6 +1658,16 @@ pub struct ImageFormatInfo {
|
||||
/// The default value is `Format::UNDEFINED`.
|
||||
pub format: Format,
|
||||
|
||||
/// The image view formats that will be allowed for the image.
|
||||
///
|
||||
/// If this is not empty, then the physical device API version must be at least 1.2, or the
|
||||
/// [`khr_image_format_list`] extension must be supported by the physical device.
|
||||
///
|
||||
/// The default value is empty.
|
||||
///
|
||||
/// [`khr_image_format_list`]: crate::device::DeviceExtensions::khr_image_format_list
|
||||
pub view_formats: Vec<Format>,
|
||||
|
||||
/// The dimension type that the image will have.
|
||||
///
|
||||
/// The default value is [`ImageType::Dim2d`].
|
||||
@ -1671,6 +1692,15 @@ pub struct ImageFormatInfo {
|
||||
/// The default value is `None`.
|
||||
pub stencil_usage: Option<ImageUsage>,
|
||||
|
||||
/// The Linux DRM format modifier information to query.
|
||||
///
|
||||
/// If this is `Some`, then the
|
||||
/// [`ext_image_drm_format_modifier`](crate::device::DeviceExtensions::ext_image_drm_format_modifier)
|
||||
/// extension must be supported by the physical device.
|
||||
///
|
||||
/// The default value is `None`.
|
||||
pub drm_format_modifier_info: Option<ImageDrmFormatModifierInfo>,
|
||||
|
||||
/// An external memory handle type that will be imported to or exported from the image.
|
||||
///
|
||||
/// This is needed to retrieve the
|
||||
@ -1693,15 +1723,6 @@ pub struct ImageFormatInfo {
|
||||
/// The default value is `None`.
|
||||
pub image_view_type: Option<ImageViewType>,
|
||||
|
||||
/// The Linux DRM format modifier information to query.
|
||||
///
|
||||
/// If this is `Some`, then the
|
||||
/// [`ext_image_drm_format_modifier`](crate::device::DeviceExtensions::ext_image_drm_format_modifier)
|
||||
/// extension must be supported by the physical device.
|
||||
///
|
||||
/// The default value is `None`.
|
||||
pub drm_format_modifier_info: Option<ImageDrmFormatModifierInfo>,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
@ -1711,13 +1732,14 @@ impl Default for ImageFormatInfo {
|
||||
Self {
|
||||
flags: ImageCreateFlags::empty(),
|
||||
format: Format::UNDEFINED,
|
||||
view_formats: Vec::new(),
|
||||
image_type: ImageType::Dim2d,
|
||||
tiling: ImageTiling::Optimal,
|
||||
usage: ImageUsage::empty(),
|
||||
stencil_usage: None,
|
||||
drm_format_modifier_info: None,
|
||||
external_memory_handle_type: None,
|
||||
image_view_type: None,
|
||||
drm_format_modifier_info: None,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -1731,13 +1753,14 @@ impl ImageFormatInfo {
|
||||
let &Self {
|
||||
flags,
|
||||
format,
|
||||
ref view_formats,
|
||||
image_type,
|
||||
tiling,
|
||||
usage,
|
||||
stencil_usage,
|
||||
ref drm_format_modifier_info,
|
||||
external_memory_handle_type,
|
||||
image_view_type,
|
||||
ref drm_format_modifier_info,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
@ -1837,6 +1860,80 @@ impl ImageFormatInfo {
|
||||
}
|
||||
}
|
||||
|
||||
if !view_formats.is_empty() {
|
||||
if !(physical_device.api_version() >= Version::V1_2
|
||||
|| physical_device.supported_extensions().khr_image_format_list)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "view_formats".into(),
|
||||
problem: "is not empty".into(),
|
||||
requires_one_of: RequiresOneOf(&[
|
||||
RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]),
|
||||
RequiresAllOf(&[Requires::DeviceExtension("khr_image_format_list")]),
|
||||
]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
for (index, view_format) in view_formats.iter().enumerate() {
|
||||
view_format
|
||||
.validate_physical_device(physical_device)
|
||||
.map_err(|err| {
|
||||
err.add_context(format!("view_formats[{}]", index))
|
||||
.set_vuids(&["VUID-VkImageFormatListCreateInfo-pViewFormats-parameter"])
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(drm_format_modifier_info) = drm_format_modifier_info {
|
||||
if !physical_device
|
||||
.supported_extensions()
|
||||
.ext_image_drm_format_modifier
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "drm_format_modifier_info".into(),
|
||||
problem: "is `Some`".into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
|
||||
"ext_image_drm_format_modifier",
|
||||
)])]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
drm_format_modifier_info
|
||||
.validate(physical_device)
|
||||
.map_err(|err| err.add_context("drm_format_modifier_info"))?;
|
||||
|
||||
if tiling != ImageTiling::DrmFormatModifier {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`drm_format_modifier_info` is `Some` but \
|
||||
`tiling` is not `ImageTiling::DrmFormatModifier`"
|
||||
.into(),
|
||||
vuids: &[" VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) && view_formats.is_empty() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`tiling` is `ImageTiling::DrmFormatModifier`, and \
|
||||
`flags` contains `ImageCreateFlags::MUTABLE_FORMAT`, but \
|
||||
`view_formats` is empty"
|
||||
.into(),
|
||||
vuids: &["VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02313"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
} else if tiling == ImageTiling::DrmFormatModifier {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`tiling` is `ImageTiling::DrmFormatModifier`, but \
|
||||
`drm_format_modifier_info` is `None`"
|
||||
.into(),
|
||||
vuids: &[" VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(handle_type) = external_memory_handle_type {
|
||||
if !(physical_device.api_version() >= Version::V1_1
|
||||
|| physical_device
|
||||
@ -1885,54 +1982,6 @@ impl ImageFormatInfo {
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Some(drm_format_modifier_info) = drm_format_modifier_info {
|
||||
if !physical_device
|
||||
.supported_extensions()
|
||||
.ext_image_drm_format_modifier
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "drm_format_modifier_info".into(),
|
||||
problem: "is `Some`".into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
|
||||
"ext_image_drm_format_modifier",
|
||||
)])]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
drm_format_modifier_info
|
||||
.validate(physical_device)
|
||||
.map_err(|err| err.add_context("drm_format_modifier_info"))?;
|
||||
|
||||
if tiling != ImageTiling::DrmFormatModifier {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`drm_format_modifier_info` is `Some` but \
|
||||
`tiling` is not `ImageTiling::DrmFormatModifier`"
|
||||
.into(),
|
||||
vuids: &[" VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`tiling` is `ImageTiling::DrmFormatModifier`, but \
|
||||
`flags` contains `ImageCreateFlags::MUTABLE_FORMAT`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02313"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
} else if tiling == ImageTiling::DrmFormatModifier {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`tiling` is `ImageTiling::DrmFormatModifier`, but \
|
||||
`drm_format_modifier_info` is `None`"
|
||||
.into(),
|
||||
vuids: &[" VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ pub struct RawImage {
|
||||
image_type: ImageType,
|
||||
format: Format,
|
||||
format_features: FormatFeatures,
|
||||
view_formats: Vec<Format>,
|
||||
extent: [u32; 3],
|
||||
array_layers: u32,
|
||||
mip_levels: u32,
|
||||
@ -113,6 +114,7 @@ impl RawImage {
|
||||
flags,
|
||||
image_type,
|
||||
format,
|
||||
ref view_formats,
|
||||
extent,
|
||||
array_layers,
|
||||
mip_levels,
|
||||
@ -122,10 +124,10 @@ impl RawImage {
|
||||
stencil_usage,
|
||||
ref sharing,
|
||||
initial_layout,
|
||||
external_memory_handle_types,
|
||||
_ne: _,
|
||||
ref drm_format_modifiers,
|
||||
ref drm_format_modifier_plane_layouts,
|
||||
external_memory_handle_types,
|
||||
_ne: _,
|
||||
} = &create_info;
|
||||
|
||||
let (sharing_mode, queue_family_index_count, p_queue_family_indices) = match sharing {
|
||||
@ -137,7 +139,7 @@ impl RawImage {
|
||||
),
|
||||
};
|
||||
|
||||
let mut info_vk = ash::vk::ImageCreateInfo {
|
||||
let mut create_info_vk = ash::vk::ImageCreateInfo {
|
||||
flags: flags.into(),
|
||||
image_type: image_type.into(),
|
||||
format: format.into(),
|
||||
@ -161,6 +163,8 @@ impl RawImage {
|
||||
let drm_format_modifier_plane_layouts_vk: SmallVec<[_; 4]>;
|
||||
let mut drm_format_modifier_list_info_vk = None;
|
||||
let mut external_memory_info_vk = None;
|
||||
let mut format_list_info_vk = None;
|
||||
let format_list_view_formats_vk: Vec<_>;
|
||||
let mut stencil_usage_info_vk = None;
|
||||
|
||||
#[allow(clippy::comparison_chain)]
|
||||
@ -196,8 +200,8 @@ impl RawImage {
|
||||
},
|
||||
);
|
||||
|
||||
next.p_next = info_vk.p_next;
|
||||
info_vk.p_next = next as *const _ as *const _;
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
} else if drm_format_modifiers.len() > 1 {
|
||||
let next = drm_format_modifier_list_info_vk.insert(
|
||||
ash::vk::ImageDrmFormatModifierListCreateInfoEXT {
|
||||
@ -207,8 +211,8 @@ impl RawImage {
|
||||
},
|
||||
);
|
||||
|
||||
next.p_next = info_vk.p_next;
|
||||
info_vk.p_next = next as *const _ as *const _;
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if !external_memory_handle_types.is_empty() {
|
||||
@ -217,8 +221,25 @@ impl RawImage {
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = info_vk.p_next;
|
||||
info_vk.p_next = next as *const _ as *const _;
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if !view_formats.is_empty() {
|
||||
format_list_view_formats_vk = view_formats
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ash::vk::Format::from)
|
||||
.collect();
|
||||
|
||||
let next = format_list_info_vk.insert(ash::vk::ImageFormatListCreateInfo {
|
||||
view_format_count: format_list_view_formats_vk.len() as u32,
|
||||
p_view_formats: format_list_view_formats_vk.as_ptr(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if let Some(stencil_usage) = stencil_usage {
|
||||
@ -227,16 +248,21 @@ impl RawImage {
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = info_vk.p_next;
|
||||
info_vk.p_next = next as *const _ as *const _;
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
let handle = {
|
||||
let fns = device.fns();
|
||||
let mut output = MaybeUninit::uninit();
|
||||
(fns.v1_0.create_image)(device.handle(), &info_vk, ptr::null(), output.as_mut_ptr())
|
||||
.result()
|
||||
.map_err(VulkanError::from)?;
|
||||
(fns.v1_0.create_image)(
|
||||
device.handle(),
|
||||
&create_info_vk,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
)
|
||||
.result()
|
||||
.map_err(VulkanError::from)?;
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
@ -269,6 +295,7 @@ impl RawImage {
|
||||
flags,
|
||||
image_type,
|
||||
format,
|
||||
view_formats,
|
||||
extent,
|
||||
array_layers,
|
||||
mip_levels,
|
||||
@ -278,10 +305,10 @@ impl RawImage {
|
||||
stencil_usage,
|
||||
sharing,
|
||||
initial_layout,
|
||||
external_memory_handle_types,
|
||||
_ne: _,
|
||||
drm_format_modifiers: _,
|
||||
drm_format_modifier_plane_layouts: _,
|
||||
external_memory_handle_types,
|
||||
_ne: _,
|
||||
} = create_info;
|
||||
|
||||
let format_properties =
|
||||
@ -337,6 +364,7 @@ impl RawImage {
|
||||
image_type,
|
||||
format,
|
||||
format_features,
|
||||
view_formats,
|
||||
extent,
|
||||
array_layers,
|
||||
mip_levels,
|
||||
@ -927,12 +955,11 @@ impl RawImage {
|
||||
physical_device.image_format_properties_unchecked(ImageFormatInfo {
|
||||
flags: self.flags,
|
||||
format: self.format,
|
||||
view_formats: self.view_formats.clone(),
|
||||
image_type: self.image_type,
|
||||
tiling: self.tiling,
|
||||
usage: self.usage,
|
||||
stencil_usage: self.stencil_usage,
|
||||
external_memory_handle_type: Some(handle_type),
|
||||
image_view_type: None,
|
||||
drm_format_modifier_info: self.drm_format_modifier().map(
|
||||
|(drm_format_modifier, _)| ImageDrmFormatModifierInfo {
|
||||
drm_format_modifier,
|
||||
@ -940,6 +967,8 @@ impl RawImage {
|
||||
_ne: crate::NonExhaustive(()),
|
||||
},
|
||||
),
|
||||
external_memory_handle_type: Some(handle_type),
|
||||
image_view_type: None,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
})
|
||||
}
|
||||
@ -1222,6 +1251,12 @@ impl RawImage {
|
||||
self.format_features
|
||||
}
|
||||
|
||||
/// Returns the formats that an image view created from this image can have.
|
||||
#[inline]
|
||||
pub fn view_formats(&self) -> &[Format] {
|
||||
&self.view_formats
|
||||
}
|
||||
|
||||
/// Returns the extent of the image.
|
||||
#[inline]
|
||||
pub fn extent(&self) -> [u32; 3] {
|
||||
@ -1626,9 +1661,9 @@ impl_id_counter!(RawImage);
|
||||
/// Parameters to create a new `Image`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ImageCreateInfo {
|
||||
/// Flags to enable.
|
||||
/// Additional properties of the image.
|
||||
///
|
||||
/// The default value is [`ImageCreateFlags::empty()`].
|
||||
/// The default value is empty.
|
||||
pub flags: ImageCreateFlags,
|
||||
|
||||
/// The basic image dimensionality to create the image with.
|
||||
@ -1641,6 +1676,27 @@ pub struct ImageCreateInfo {
|
||||
/// The default value is `Format::UNDEFINED`.
|
||||
pub format: Format,
|
||||
|
||||
/// The formats that an image view can have when it is created from this image.
|
||||
///
|
||||
/// If the list is not empty, and `flags` does not contain [`ImageCreateFlags::MUTABLE_FORMAT`],
|
||||
/// then the list must contain at most one element, otherwise any number of elements are
|
||||
/// allowed. The view formats must be compatible with `format`. If `flags` also contains
|
||||
/// [`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`], then the view formats can also be
|
||||
/// uncompressed formats that are merely size-compatible with `format`.
|
||||
///
|
||||
/// If the list is empty, then depending on `flags`, a view must have the same format as
|
||||
/// `format`, can have any compatible format, or additionally any uncompressed size-compatible
|
||||
/// format. However, this is less efficient than specifying the possible view formats
|
||||
/// in advance.
|
||||
///
|
||||
/// If this is not empty, then the device API version must be at least 1.2, or the
|
||||
/// [`khr_image_format_list`] extension must be enabled on the device.
|
||||
///
|
||||
/// The default value is empty.
|
||||
///
|
||||
/// [`khr_image_format_list`]: crate::device::DeviceExtensions::khr_image_format_list
|
||||
pub view_formats: Vec<Format>,
|
||||
|
||||
/// The width, height and depth of the image.
|
||||
///
|
||||
/// If `image_type` is `ImageType::Dim2d`, then the depth must be 1.
|
||||
@ -1681,7 +1737,7 @@ pub struct ImageCreateInfo {
|
||||
|
||||
/// How the image is going to be used.
|
||||
///
|
||||
/// The default value is [`ImageUsage::empty()`], which must be overridden.
|
||||
/// The default value is empty, which must be overridden.
|
||||
pub usage: ImageUsage,
|
||||
|
||||
/// How the stencil aspect of the image is going to be used, if different from the regular
|
||||
@ -1704,16 +1760,6 @@ pub struct ImageCreateInfo {
|
||||
/// The default value is [`ImageLayout::Undefined`].
|
||||
pub initial_layout: ImageLayout,
|
||||
|
||||
/// The external memory handle types that are going to be used with the image.
|
||||
///
|
||||
/// If any of the fields in this value are set, the device must either support API version 1.1
|
||||
/// or the [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
|
||||
/// extension must be enabled, and `initial_layout` must be set to
|
||||
/// [`ImageLayout::Undefined`].
|
||||
///
|
||||
/// The default value is [`ExternalMemoryHandleTypes::empty()`].
|
||||
pub external_memory_handle_types: ExternalMemoryHandleTypes,
|
||||
|
||||
/// The Linux DRM format modifiers that the image should be created with.
|
||||
///
|
||||
/// If this is not empty, then the
|
||||
@ -1721,7 +1767,7 @@ pub struct ImageCreateInfo {
|
||||
/// extension must be enabled on the device.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub drm_format_modifiers: SmallVec<[u64; 1]>,
|
||||
pub drm_format_modifiers: Vec<u64>,
|
||||
|
||||
/// If `drm_format_modifiers` contains one element, provides the subresource layouts of each
|
||||
/// memory plane of the image. The number of elements must equal
|
||||
@ -1732,11 +1778,22 @@ pub struct ImageCreateInfo {
|
||||
/// - If `image_type` is not [`ImageType::Dim3d`] or `extent[2]` is 1, then
|
||||
/// [`SubresourceLayout::depth_pitch`] must be `None`.
|
||||
///
|
||||
/// If `drm_format_modifiers` does not contain one element, then
|
||||
/// this must be empty.
|
||||
/// If `drm_format_modifiers` does not contain one element, then this must be empty.
|
||||
///
|
||||
/// The default value is empty.
|
||||
///
|
||||
/// [`DrmFormatModifierProperties::drm_format_modifier_plane_count`]: crate::format::DrmFormatModifierProperties::drm_format_modifier_plane_count
|
||||
pub drm_format_modifier_plane_layouts: SmallVec<[SubresourceLayout; 4]>,
|
||||
pub drm_format_modifier_plane_layouts: Vec<SubresourceLayout>,
|
||||
|
||||
/// The external memory handle types that are going to be used with the image.
|
||||
///
|
||||
/// If this is not empty, then the device API version must be at least 1.1, or the
|
||||
/// [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
|
||||
/// extension must be enabled on the device. `initial_layout` must be set to
|
||||
/// [`ImageLayout::Undefined`].
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub external_memory_handle_types: ExternalMemoryHandleTypes,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
@ -1748,6 +1805,7 @@ impl Default for ImageCreateInfo {
|
||||
flags: ImageCreateFlags::empty(),
|
||||
image_type: ImageType::Dim2d,
|
||||
format: Format::UNDEFINED,
|
||||
view_formats: Vec::new(),
|
||||
extent: [0; 3],
|
||||
array_layers: 1,
|
||||
mip_levels: 1,
|
||||
@ -1758,8 +1816,8 @@ impl Default for ImageCreateInfo {
|
||||
sharing: Sharing::Exclusive,
|
||||
initial_layout: ImageLayout::Undefined,
|
||||
external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
|
||||
drm_format_modifiers: SmallVec::new(),
|
||||
drm_format_modifier_plane_layouts: SmallVec::new(),
|
||||
drm_format_modifiers: Vec::new(),
|
||||
drm_format_modifier_plane_layouts: Vec::new(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -1771,6 +1829,7 @@ impl ImageCreateInfo {
|
||||
flags,
|
||||
image_type,
|
||||
format,
|
||||
ref view_formats,
|
||||
extent,
|
||||
array_layers,
|
||||
mip_levels,
|
||||
@ -1780,10 +1839,10 @@ impl ImageCreateInfo {
|
||||
stencil_usage,
|
||||
ref sharing,
|
||||
initial_layout,
|
||||
external_memory_handle_types,
|
||||
_ne: _,
|
||||
ref drm_format_modifiers,
|
||||
ref drm_format_modifier_plane_layouts,
|
||||
external_memory_handle_types,
|
||||
_ne: _,
|
||||
} = self;
|
||||
|
||||
let physical_device = device.physical_device();
|
||||
@ -1875,6 +1934,76 @@ impl ImageCreateInfo {
|
||||
}));
|
||||
}
|
||||
|
||||
if !view_formats.is_empty() {
|
||||
if !(device.api_version() >= Version::V1_2
|
||||
|| device.enabled_extensions().khr_image_format_list)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "view_formats".into(),
|
||||
problem: "is not empty".into(),
|
||||
requires_one_of: RequiresOneOf(&[
|
||||
RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]),
|
||||
RequiresAllOf(&[Requires::DeviceExtension("khr_image_format_list")]),
|
||||
]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) && view_formats.len() != 1 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`flags` does not contain `ImageCreateFlags::MUTABLE_FORMAT`, but \
|
||||
`view_formats` contains more than one element"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-flags-04738"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
for (index, &view_format) in view_formats.iter().enumerate() {
|
||||
view_format.validate_device(device).map_err(|err| {
|
||||
err.add_context(format!("view_formats[{}]", index))
|
||||
.set_vuids(&["VUID-VkImageFormatListCreateInfo-pViewFormats-parameter"])
|
||||
})?;
|
||||
|
||||
if flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
|
||||
&& view_format.compression().is_none()
|
||||
{
|
||||
if !(view_format.compatibility() == format.compatibility()
|
||||
|| view_format.block_size() == format.block_size())
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"`flags` contains \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`view_formats[{}]` is an uncompressed format, but \
|
||||
it is not compatible with `format`, and \
|
||||
does not have an equal block size",
|
||||
index
|
||||
)
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-pNext-06722"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
if view_format.compatibility() != format.compatibility() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"`flags` does not contain \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, or \
|
||||
`view_format[{}]` is a compressed format, but \
|
||||
it is not compatible with `create_info.format`",
|
||||
index
|
||||
)
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-pNext-06722"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match image_type {
|
||||
ImageType::Dim1d => {
|
||||
if extent[1] != 1 {
|
||||
@ -2431,7 +2560,7 @@ impl ImageCreateInfo {
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`flags` contains `ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, \
|
||||
but `format` is not a compressed format"
|
||||
but `format` is not a compressed format"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-flags-01572"],
|
||||
..Default::default()
|
||||
@ -2442,7 +2571,7 @@ impl ImageCreateInfo {
|
||||
if format.planes().len() < 2 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`flags` contains `ImageCreateFlags::DISJOINT`, but `format` \
|
||||
is not a multi-planat format"
|
||||
is not a multi-planat format"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-format-01577"],
|
||||
..Default::default()
|
||||
@ -2506,41 +2635,6 @@ impl ImageCreateInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/* External memory handles */
|
||||
|
||||
if !external_memory_handle_types.is_empty() {
|
||||
if !(device.api_version() >= Version::V1_1
|
||||
|| device.enabled_extensions().khr_external_memory)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "external_memory_handle_types".into(),
|
||||
problem: "is not empty".into(),
|
||||
requires_one_of: RequiresOneOf(&[
|
||||
RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]),
|
||||
RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]),
|
||||
]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
external_memory_handle_types
|
||||
.validate_device(device)
|
||||
.map_err(|err| {
|
||||
err.add_context("external_memory_handle_types")
|
||||
.set_vuids(&["VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter"])
|
||||
})?;
|
||||
|
||||
if initial_layout != ImageLayout::Undefined {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`external_memory_handle_types` is not empty, but \
|
||||
`initial_layout` is not `ImageLayout::Undefined`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-pNext-01443"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if !drm_format_modifiers.is_empty() {
|
||||
// This implicitly checks for the enabled extension too,
|
||||
// so no need to check that separately.
|
||||
@ -2554,10 +2648,11 @@ impl ImageCreateInfo {
|
||||
}));
|
||||
}
|
||||
|
||||
if flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) {
|
||||
if flags.intersects(ImageCreateFlags::MUTABLE_FORMAT) && view_formats.is_empty() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`tiling` is `ImageTiling::DrmFormatModifier`, but \
|
||||
`flags` contains `ImageCreateFlags::MUTABLE_FORMAT`"
|
||||
problem: "`tiling` is `ImageTiling::DrmFormatModifier`, and \
|
||||
`flags` contains `ImageCreateFlags::MUTABLE_FORMAT`, but \
|
||||
`view_formats` is empty"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-tiling-02353"],
|
||||
..Default::default()
|
||||
@ -2673,6 +2768,39 @@ impl ImageCreateInfo {
|
||||
}
|
||||
}
|
||||
|
||||
if !external_memory_handle_types.is_empty() {
|
||||
if !(device.api_version() >= Version::V1_1
|
||||
|| device.enabled_extensions().khr_external_memory)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "external_memory_handle_types".into(),
|
||||
problem: "is not empty".into(),
|
||||
requires_one_of: RequiresOneOf(&[
|
||||
RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]),
|
||||
RequiresAllOf(&[Requires::DeviceExtension("khr_external_memory")]),
|
||||
]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
external_memory_handle_types
|
||||
.validate_device(device)
|
||||
.map_err(|err| {
|
||||
err.add_context("external_memory_handle_types")
|
||||
.set_vuids(&["VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter"])
|
||||
})?;
|
||||
|
||||
if initial_layout != ImageLayout::Undefined {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`external_memory_handle_types` is not empty, but \
|
||||
`initial_layout` is not `ImageLayout::Undefined`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageCreateInfo-pNext-01443"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Some device limits can be exceeded, but only for particular image configurations, which
|
||||
must be queried with `image_format_properties`. See:
|
||||
|
@ -381,6 +381,16 @@ impl ImageView {
|
||||
/* Check flags requirements */
|
||||
|
||||
if format != image.format() {
|
||||
if !image.flags().intersects(ImageCreateFlags::MUTABLE_FORMAT) {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`create_info.format` does not equal `image.format()`, but \
|
||||
`image.flags()` does not contain `ImageCreateFlags::MUTABLE_FORMAT`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-01762"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !image.format().planes().is_empty()
|
||||
&& subresource_range.aspects.intersects(ImageAspects::COLOR)
|
||||
{
|
||||
@ -394,46 +404,29 @@ impl ImageView {
|
||||
}));
|
||||
}
|
||||
|
||||
if !image.flags().intersects(ImageCreateFlags::MUTABLE_FORMAT) {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`create_info.format` does not equal `image.format()`, but \
|
||||
`image.flags()` does not contain `ImageCreateFlags::MUTABLE_FORMAT`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-01762"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
// TODO: it is unclear what the number of bits is for compressed formats.
|
||||
// See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2361
|
||||
if device.enabled_extensions().khr_portability_subset
|
||||
&& !device.enabled_features().image_view_format_reinterpretation
|
||||
&& format.components() != image.format().components()
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "this device is a portability subset device, and \
|
||||
`create_info.format` does not have the same components and \
|
||||
number of bits per component as `image.format()`"
|
||||
.into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||
"image_view_format_reinterpretation",
|
||||
)])]),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-imageViewFormatReinterpretation-04466"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if image
|
||||
if !image.view_formats().is_empty() {
|
||||
if !image.view_formats().contains(&format) {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.view_formats()` is not empty, but it does not contain \
|
||||
`create_info.format`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-pNext-01585"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
} else if image
|
||||
.flags()
|
||||
.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
|
||||
&& format.compression().is_none()
|
||||
{
|
||||
if !(format.compatibility() == image.format().compatibility()
|
||||
|| format.block_size() == image.format().block_size())
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.flags()` contains \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, but \
|
||||
`create_info.format` is not compatible with `image.format()`, or \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`create_info.format` is an uncompressed format, but \
|
||||
it is not compatible with `image.format()`, and \
|
||||
does not have an equal block size"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-01583"],
|
||||
@ -441,41 +434,40 @@ impl ImageView {
|
||||
}));
|
||||
}
|
||||
|
||||
if format.compression().is_none() {
|
||||
if subresource_range.array_layers.len() != 1 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.flags()` contains \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`create_info.format` is not a compressed format, but \
|
||||
the length of `create_info.subresource_range.array_layers` \
|
||||
is not 1"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-07072"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
if subresource_range.array_layers.len() != 1 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.flags()` contains \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`create_info.format` is an uncompressed format, but \
|
||||
the length of `create_info.subresource_range.array_layers` \
|
||||
is not 1"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-07072"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if subresource_range.mip_levels.len() != 1 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.flags()` contains \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`create_info.format` is not a compressed format, but \
|
||||
the length of `create_info.subresource_range.mip_levels` \
|
||||
is not 1"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-07072"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
if subresource_range.mip_levels.len() != 1 {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.flags()` contains \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`create_info.format` is an uncompressed format, but \
|
||||
the length of `create_info.subresource_range.mip_levels` \
|
||||
is not 1"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-07072"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
if image.format().planes().is_empty() {
|
||||
if format.compatibility() != image.format().compatibility() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`image.flags()` does not contain \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, and \
|
||||
`ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE`, or \
|
||||
`create_info.format` is a compressed format, and \
|
||||
`image.format()` is not a multi-planar format, but \
|
||||
is not compatible with `create_info.format`"
|
||||
it is not compatible with `create_info.format`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-image-01761"],
|
||||
..Default::default()
|
||||
@ -509,6 +501,25 @@ impl ImageView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: it is unclear what the number of bits is for compressed formats.
|
||||
// See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2361
|
||||
if device.enabled_extensions().khr_portability_subset
|
||||
&& !device.enabled_features().image_view_format_reinterpretation
|
||||
&& format.components() != image.format().components()
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "this device is a portability subset device, and \
|
||||
`create_info.format` does not have the same components and \
|
||||
number of bits per component as `image.format()`"
|
||||
.into(),
|
||||
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature(
|
||||
"image_view_format_reinterpretation",
|
||||
)])]),
|
||||
vuids: &["VUID-VkImageViewCreateInfo-imageViewFormatReinterpretation-04466"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(chroma_sampling) = format.ycbcr_chroma_sampling() {
|
||||
|
@ -334,11 +334,12 @@ mod surface;
|
||||
use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
format::Format,
|
||||
image::{Image, ImageFormatInfo, ImageTiling, ImageType, ImageUsage},
|
||||
image::{Image, ImageCreateFlags, ImageFormatInfo, ImageTiling, ImageType, ImageUsage},
|
||||
instance::InstanceOwnedDebugWrapper,
|
||||
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum},
|
||||
sync::Sharing,
|
||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject,
|
||||
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
|
||||
VulkanObject,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smallvec::SmallVec;
|
||||
@ -364,6 +365,7 @@ pub struct Swapchain {
|
||||
flags: SwapchainCreateFlags,
|
||||
min_image_count: u32,
|
||||
image_format: Format,
|
||||
image_view_formats: Vec<Format>,
|
||||
image_color_space: ColorSpace,
|
||||
image_extent: [u32; 2],
|
||||
image_array_layers: u32,
|
||||
@ -538,6 +540,7 @@ impl Swapchain {
|
||||
flags: _,
|
||||
min_image_count,
|
||||
image_format,
|
||||
image_view_formats: _,
|
||||
image_color_space,
|
||||
image_extent,
|
||||
image_array_layers,
|
||||
@ -996,6 +999,7 @@ impl Swapchain {
|
||||
flags,
|
||||
min_image_count,
|
||||
image_format,
|
||||
ref image_view_formats,
|
||||
image_color_space,
|
||||
image_extent,
|
||||
image_array_layers,
|
||||
@ -1045,11 +1049,53 @@ impl Swapchain {
|
||||
old_swapchain: old_swapchain.map_or(ash::vk::SwapchainKHR::null(), |os| os.handle),
|
||||
..Default::default()
|
||||
};
|
||||
let mut format_list_info_vk = None;
|
||||
let format_list_view_formats_vk: Vec<_>;
|
||||
let mut full_screen_exclusive_info_vk = None;
|
||||
let mut full_screen_exclusive_win32_info_vk = None;
|
||||
let mut present_modes_info_vk = None;
|
||||
let present_modes_vk: SmallVec<[ash::vk::PresentModeKHR; PresentMode::COUNT]>;
|
||||
let mut present_scaling_info_vk = None;
|
||||
let mut full_screen_exclusive_info_vk = None;
|
||||
let mut full_screen_exclusive_win32_info_vk = None;
|
||||
|
||||
if !image_view_formats.is_empty() {
|
||||
format_list_view_formats_vk = image_view_formats
|
||||
.iter()
|
||||
.copied()
|
||||
.map(ash::vk::Format::from)
|
||||
.collect();
|
||||
|
||||
let next = format_list_info_vk.insert(ash::vk::ImageFormatListCreateInfo {
|
||||
view_format_count: format_list_view_formats_vk.len() as u32,
|
||||
p_view_formats: format_list_view_formats_vk.as_ptr(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = create_info_vk.p_next;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if full_screen_exclusive != FullScreenExclusive::Default {
|
||||
let next =
|
||||
full_screen_exclusive_info_vk.insert(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
|
||||
full_screen_exclusive: full_screen_exclusive.into(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = create_info_vk.p_next as *mut _;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if let Some(Win32Monitor(hmonitor)) = win32_monitor {
|
||||
let next = full_screen_exclusive_win32_info_vk.insert(
|
||||
ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
|
||||
hmonitor,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
next.p_next = create_info_vk.p_next as *mut _;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if !present_modes.is_empty() {
|
||||
present_modes_vk = present_modes.iter().copied().map(Into::into).collect();
|
||||
@ -1079,29 +1125,6 @@ impl Swapchain {
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if full_screen_exclusive != FullScreenExclusive::Default {
|
||||
let next =
|
||||
full_screen_exclusive_info_vk.insert(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
|
||||
full_screen_exclusive: full_screen_exclusive.into(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
next.p_next = create_info_vk.p_next as *mut _;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
if let Some(Win32Monitor(hmonitor)) = win32_monitor {
|
||||
let next = full_screen_exclusive_win32_info_vk.insert(
|
||||
ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
|
||||
hmonitor,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
next.p_next = create_info_vk.p_next as *mut _;
|
||||
create_info_vk.p_next = next as *const _ as *const _;
|
||||
}
|
||||
|
||||
let fns = device.fns();
|
||||
|
||||
let handle = {
|
||||
@ -1169,6 +1192,7 @@ impl Swapchain {
|
||||
flags,
|
||||
min_image_count,
|
||||
image_format,
|
||||
image_view_formats,
|
||||
image_color_space,
|
||||
image_extent,
|
||||
image_array_layers,
|
||||
@ -1195,6 +1219,7 @@ impl Swapchain {
|
||||
flags,
|
||||
min_image_count,
|
||||
image_format,
|
||||
image_view_formats,
|
||||
image_color_space,
|
||||
image_extent,
|
||||
image_array_layers,
|
||||
@ -1245,6 +1270,7 @@ impl Swapchain {
|
||||
flags: self.flags,
|
||||
min_image_count: self.min_image_count,
|
||||
image_format: self.image_format,
|
||||
image_view_formats: self.image_view_formats.clone(),
|
||||
image_color_space: self.image_color_space,
|
||||
image_extent: self.image_extent,
|
||||
image_array_layers: self.image_array_layers,
|
||||
@ -1296,6 +1322,12 @@ impl Swapchain {
|
||||
self.image_format
|
||||
}
|
||||
|
||||
/// Returns the formats that an image view created from a swapchain image can have.
|
||||
#[inline]
|
||||
pub fn image_view_formats(&self) -> &[Format] {
|
||||
&self.image_view_formats
|
||||
}
|
||||
|
||||
/// Returns the color space of the images of the swapchain.
|
||||
#[inline]
|
||||
pub fn image_color_space(&self) -> ColorSpace {
|
||||
@ -1583,6 +1615,24 @@ pub struct SwapchainCreateInfo {
|
||||
/// The default value is `Format::UNDEFINED`.
|
||||
pub image_format: Format,
|
||||
|
||||
/// The formats that an image view can have when it is created from one of the swapchain images.
|
||||
///
|
||||
/// If the list is not empty, and `flags` does not contain
|
||||
/// [`SwapchainCreateFlags::MUTABLE_FORMAT`], then the list must contain at most one element,
|
||||
/// otherwise any number of elements are allowed.
|
||||
/// The view formats must be compatible with `format`.
|
||||
///
|
||||
/// If `flags` contains [`SwapchainCreateFlags::MUTABLE_FORMAT`], then the list must contain
|
||||
/// `image_format.
|
||||
///
|
||||
/// If this is not empty, then the device API version must be at least 1.2, or the
|
||||
/// [`khr_image_format_list`] extension must be enabled on the device.
|
||||
///
|
||||
/// The default value is empty.
|
||||
///
|
||||
/// [`khr_image_format_list`]: crate::device::DeviceExtensions::khr_image_format_list
|
||||
pub image_view_formats: Vec<Format>,
|
||||
|
||||
/// The color space of the created images.
|
||||
///
|
||||
/// The default value is [`ColorSpace::SrgbNonLinear`].
|
||||
@ -1699,6 +1749,7 @@ impl Default for SwapchainCreateInfo {
|
||||
flags: SwapchainCreateFlags::empty(),
|
||||
min_image_count: 2,
|
||||
image_format: Format::UNDEFINED,
|
||||
image_view_formats: Vec::new(),
|
||||
image_color_space: ColorSpace::SrgbNonLinear,
|
||||
image_extent: [0, 0],
|
||||
image_array_layers: 1,
|
||||
@ -1724,6 +1775,7 @@ impl SwapchainCreateInfo {
|
||||
flags,
|
||||
min_image_count: _,
|
||||
image_format,
|
||||
ref image_view_formats,
|
||||
image_color_space,
|
||||
image_extent,
|
||||
image_array_layers,
|
||||
@ -1879,6 +1931,65 @@ impl SwapchainCreateInfo {
|
||||
}));
|
||||
}
|
||||
|
||||
if flags.intersects(SwapchainCreateFlags::MUTABLE_FORMAT)
|
||||
&& !image_view_formats.contains(&image_format)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`flags` contains `SwapchainCreateFlags::MUTABLE_FORMAT`, but \
|
||||
`image_view_formats` does not contain `image_format`"
|
||||
.into(),
|
||||
vuids: &["VUID-VkSwapchainCreateInfoKHR-flags-03168"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !image_view_formats.is_empty() {
|
||||
if !(device.api_version() >= Version::V1_2
|
||||
|| device.enabled_extensions().khr_image_format_list)
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
context: "image_view_formats".into(),
|
||||
problem: "is not empty".into(),
|
||||
requires_one_of: RequiresOneOf(&[
|
||||
RequiresAllOf(&[Requires::APIVersion(Version::V1_2)]),
|
||||
RequiresAllOf(&[Requires::DeviceExtension("khr_image_format_list")]),
|
||||
]),
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
if !flags.intersects(SwapchainCreateFlags::MUTABLE_FORMAT)
|
||||
&& image_view_formats.len() != 1
|
||||
{
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: "`flags` does not contain `SwapchainCreateFlags::MUTABLE_FORMAT`, \
|
||||
but `image_view_formats` contains more than one element"
|
||||
.into(),
|
||||
vuids: &["VUID-VkSwapchainCreateInfoKHR-flags-04100"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
|
||||
for (index, &image_view_format) in image_view_formats.iter().enumerate() {
|
||||
image_view_format.validate_device(device).map_err(|err| {
|
||||
err.add_context(format!("image_view_formats[{}]", index))
|
||||
.set_vuids(&["VUID-VkImageFormatListCreateInfo-pViewFormats-parameter"])
|
||||
})?;
|
||||
|
||||
if image_view_format.compatibility() != image_format.compatibility() {
|
||||
return Err(Box::new(ValidationError {
|
||||
problem: format!(
|
||||
"`image_view_formats[{}]` is not compatible with `image_format`",
|
||||
index
|
||||
)
|
||||
.into(),
|
||||
vuids: &["VUID-VkSwapchainCreateInfoKHR-pNext-04099"],
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !present_modes.is_empty() {
|
||||
if !device.enabled_extensions().ext_swapchain_maintenance1 {
|
||||
return Err(Box::new(ValidationError {
|
||||
@ -1995,22 +2106,26 @@ vulkan_bitflags! {
|
||||
SwapchainCreateFlags = SwapchainCreateFlagsKHR(u32);
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
SPLIT_INSTANCE_BIND_REGIONS = SPLIT_INSTANCE_BIND_REGIONS {
|
||||
// Provided by VK_VERSION_1_1 with VK_KHR_swapchain, VK_KHR_device_group with VK_KHR_swapchain
|
||||
},*/
|
||||
/// Creates swapchain images with the [`ImageCreateFlags::SPLIT_INSTANCE_BIND_REGIONS`] flag.
|
||||
SPLIT_INSTANCE_BIND_REGIONS = SPLIT_INSTANCE_BIND_REGIONS
|
||||
RequiresOneOf([
|
||||
RequiresAllOf([APIVersion(V1_1)]),
|
||||
RequiresAllOf([DeviceExtension(khr_device_group)]),
|
||||
]),*/
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
PROTECTED = PROTECTED {
|
||||
// Provided by VK_VERSION_1_1 with VK_KHR_swapchain
|
||||
},*/
|
||||
/// Creates swapchain images with the [`ImageCreateFlags::PROTECTED`] flag.
|
||||
PROTECTED = PROTECTED
|
||||
RequiresOneOf([
|
||||
RequiresAllOf([APIVersion(V1_1)]),
|
||||
]),*/
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
MUTABLE_FORMAT = MUTABLE_FORMAT {
|
||||
device_extensions: [khr_swapchain_mutable_format],
|
||||
},*/
|
||||
/// Creates swapchain images with both the [`ImageCreateFlags::MUTABLE_FORMAT`] and
|
||||
/// [`ImageCreateFlags::EXTENDED_USAGE`] flags.
|
||||
MUTABLE_FORMAT = MUTABLE_FORMAT
|
||||
RequiresOneOf([
|
||||
RequiresAllOf([DeviceExtension(khr_swapchain_mutable_format)]),
|
||||
]),
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
@ -2019,6 +2134,30 @@ vulkan_bitflags! {
|
||||
},*/
|
||||
}
|
||||
|
||||
impl From<SwapchainCreateFlags> for ImageCreateFlags {
|
||||
#[inline]
|
||||
fn from(flags: SwapchainCreateFlags) -> Self {
|
||||
// Per https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkCreateSwapchainKHR.html#_description
|
||||
let mut result = ImageCreateFlags::empty();
|
||||
|
||||
/* TODO: enable
|
||||
if flags.intersects(SwapchainCreateFlags::SPLIT_INSTANCE_BIND_REGIONS) {
|
||||
result |= ImageCreateFlags::SPLIT_INSTANCE_BIND_REGIONS;
|
||||
} */
|
||||
|
||||
/* TODO: enable
|
||||
if flags.intersects(SwapchainCreateFlags::PROTECTED) {
|
||||
result |= ImageCreateFlags::PROTECTED;
|
||||
} */
|
||||
|
||||
if flags.intersects(SwapchainCreateFlags::MUTABLE_FORMAT) {
|
||||
result |= ImageCreateFlags::MUTABLE_FORMAT | ImageCreateFlags::EXTENDED_USAGE;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_bitflags_enum! {
|
||||
#[non_exhaustive]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user