mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Macrofy all Vulkan bitflag and enum types, check for device support (#1964)
This commit is contained in:
parent
f96768f556
commit
2705984c77
@ -43,10 +43,10 @@ fn main() {
|
||||
// Choose which physical device to use.
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
// The Vulkan specs guarantee that a compliant implementation must provide at least one queue
|
||||
// that supports compute operations.
|
||||
@ -60,6 +60,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -143,7 +144,7 @@ fn main() {
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::none()
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data_iter,
|
||||
|
@ -86,10 +86,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -101,6 +101,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -140,7 +141,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
|
@ -57,10 +57,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -72,6 +72,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -110,7 +111,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
|
@ -37,7 +37,7 @@ fn main() {
|
||||
// this example. First, enable debugging using this extension: VK_EXT_debug_utils
|
||||
let extensions = InstanceExtensions {
|
||||
ext_debug_utils: true,
|
||||
..InstanceExtensions::none()
|
||||
..InstanceExtensions::empty()
|
||||
};
|
||||
|
||||
let library = VulkanLibrary::new().unwrap();
|
||||
@ -93,8 +93,14 @@ fn main() {
|
||||
warning: true,
|
||||
information: true,
|
||||
verbose: true,
|
||||
..DebugUtilsMessageSeverity::empty()
|
||||
},
|
||||
message_type: DebugUtilsMessageType {
|
||||
general: true,
|
||||
validation: true,
|
||||
performance: true,
|
||||
..DebugUtilsMessageType::empty()
|
||||
},
|
||||
message_type: DebugUtilsMessageType::all(),
|
||||
..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| {
|
||||
let severity = if msg.severity.error {
|
||||
"error"
|
||||
@ -136,10 +142,10 @@ fn main() {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.map(|p| {
|
||||
p.queue_families()
|
||||
.next()
|
||||
@ -152,6 +158,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.expect("no device available");
|
||||
|
||||
|
@ -58,7 +58,10 @@ impl AmbientLightingSystem {
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -59,7 +59,10 @@ impl DirectionalLightingSystem {
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -58,7 +58,10 @@ impl PointLightingSystem {
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -147,7 +147,11 @@ impl FrameSystem {
|
||||
gfx_queue.device().clone(),
|
||||
[1, 1],
|
||||
Format::A2B10G10R10_UNORM_PACK32,
|
||||
ImageUsage::transient_input_attachment(),
|
||||
ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@ -157,7 +161,11 @@ impl FrameSystem {
|
||||
gfx_queue.device().clone(),
|
||||
[1, 1],
|
||||
Format::R16G16B16A16_SFLOAT,
|
||||
ImageUsage::transient_input_attachment(),
|
||||
ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@ -167,7 +175,11 @@ impl FrameSystem {
|
||||
gfx_queue.device().clone(),
|
||||
[1, 1],
|
||||
Format::D16_UNORM,
|
||||
ImageUsage::transient_input_attachment(),
|
||||
ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@ -235,7 +247,11 @@ impl FrameSystem {
|
||||
self.gfx_queue.device().clone(),
|
||||
img_dims,
|
||||
Format::A2B10G10R10_UNORM_PACK32,
|
||||
ImageUsage::transient_input_attachment(),
|
||||
ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@ -245,7 +261,11 @@ impl FrameSystem {
|
||||
self.gfx_queue.device().clone(),
|
||||
img_dims,
|
||||
Format::R16G16B16A16_SFLOAT,
|
||||
ImageUsage::transient_input_attachment(),
|
||||
ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
@ -255,7 +275,11 @@ impl FrameSystem {
|
||||
self.gfx_queue.device().clone(),
|
||||
img_dims,
|
||||
Format::D16_UNORM,
|
||||
ImageUsage::transient_input_attachment(),
|
||||
ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
|
@ -76,10 +76,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -91,6 +91,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -129,7 +130,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
|
@ -53,7 +53,10 @@ impl TriangleDrawSystem {
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -45,10 +45,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -60,6 +60,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -153,7 +154,10 @@ fn main() {
|
||||
|
||||
let input_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
uniform_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
aligned_data.into_iter(),
|
||||
)
|
||||
@ -161,7 +165,10 @@ fn main() {
|
||||
|
||||
let output_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
(0..12).map(|_| 0u32),
|
||||
)
|
||||
|
@ -41,7 +41,7 @@ fn main() {
|
||||
// about the device workgroup size limits
|
||||
khr_get_physical_device_properties2: true,
|
||||
|
||||
..InstanceExtensions::none()
|
||||
..InstanceExtensions::empty()
|
||||
},
|
||||
// Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK)
|
||||
enumerate_portability: true,
|
||||
@ -51,10 +51,10 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -66,6 +66,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -207,7 +208,10 @@ fn main() {
|
||||
|
||||
let buf = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
(0..1024 * 1024 * 4).map(|_| 0u8),
|
||||
)
|
||||
|
@ -102,11 +102,11 @@ mod linux {
|
||||
sampled: true,
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
ImageCreateFlags {
|
||||
mutable_format: true,
|
||||
..ImageCreateFlags::none()
|
||||
..ImageCreateFlags::empty()
|
||||
},
|
||||
[queue.family()],
|
||||
)
|
||||
@ -123,7 +123,10 @@ mod linux {
|
||||
Semaphore::new(
|
||||
device.clone(),
|
||||
SemaphoreCreateInfo {
|
||||
export_handle_types: ExternalSemaphoreHandleTypes::posix(),
|
||||
export_handle_types: ExternalSemaphoreHandleTypes {
|
||||
opaque_fd: true,
|
||||
..ExternalSemaphoreHandleTypes::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@ -133,7 +136,10 @@ mod linux {
|
||||
Semaphore::new(
|
||||
device.clone(),
|
||||
SemaphoreCreateInfo {
|
||||
export_handle_types: ExternalSemaphoreHandleTypes::posix(),
|
||||
export_handle_types: ExternalSemaphoreHandleTypes {
|
||||
opaque_fd: true,
|
||||
..ExternalSemaphoreHandleTypes::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@ -251,7 +257,7 @@ mod linux {
|
||||
&release_sem,
|
||||
PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
);
|
||||
builder.submit(&queue).unwrap();
|
||||
@ -390,7 +396,7 @@ mod linux {
|
||||
khr_external_fence_capabilities: true,
|
||||
ext_debug_utils: true,
|
||||
|
||||
..InstanceExtensions::none()
|
||||
..InstanceExtensions::empty()
|
||||
}
|
||||
.union(&required_extensions),
|
||||
|
||||
@ -431,11 +437,11 @@ mod linux {
|
||||
khr_external_fence: true,
|
||||
khr_external_fence_fd: true,
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| {
|
||||
@ -456,6 +462,7 @@ mod linux {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -495,7 +502,10 @@ mod linux {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -523,7 +533,10 @@ mod linux {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -76,10 +76,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -91,6 +91,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -129,7 +130,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -164,7 +168,10 @@ fn main() {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
@ -215,7 +222,10 @@ fn main() {
|
||||
|
||||
let buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::transfer_src(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
image_data,
|
||||
)
|
||||
|
@ -74,10 +74,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -89,6 +89,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -127,7 +128,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -162,7 +166,10 @@ fn main() {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -80,10 +80,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -95,6 +95,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -133,7 +134,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -168,7 +172,10 @@ fn main() {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -94,10 +94,10 @@ fn main() {
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -109,6 +109,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -148,7 +149,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -238,9 +242,22 @@ fn main() {
|
||||
|
||||
// Each frame we generate a new set of vertices and each frame we need a new DrawIndirectCommand struct to
|
||||
// set the number of vertices to draw
|
||||
let indirect_args_pool: CpuBufferPool<DrawIndirectCommand> =
|
||||
CpuBufferPool::new(device.clone(), BufferUsage::all());
|
||||
let vertex_pool: CpuBufferPool<Vertex> = CpuBufferPool::new(device.clone(), BufferUsage::all());
|
||||
let indirect_args_pool: CpuBufferPool<DrawIndirectCommand> = CpuBufferPool::new(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
indirect_buffer: true,
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
);
|
||||
let vertex_pool: CpuBufferPool<Vertex> = CpuBufferPool::new(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
);
|
||||
|
||||
let compute_pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
|
@ -92,10 +92,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -107,6 +107,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -146,7 +147,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -172,7 +176,16 @@ fn main() {
|
||||
},
|
||||
];
|
||||
let vertex_buffer = {
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices).unwrap()
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
// Now we create another buffer that will store the unique data per instance.
|
||||
@ -198,9 +211,16 @@ fn main() {
|
||||
}
|
||||
data
|
||||
};
|
||||
let instance_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, instances)
|
||||
.unwrap();
|
||||
let instance_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
instances,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mod vs {
|
||||
vulkano_shaders::shader! {
|
||||
|
@ -43,7 +43,10 @@ impl FractalComputePipeline {
|
||||
let palette_size = colors.len() as i32;
|
||||
let palette = CpuAccessibleBuffer::from_iter(
|
||||
queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
colors,
|
||||
)
|
||||
@ -82,7 +85,10 @@ impl FractalComputePipeline {
|
||||
}
|
||||
self.palette = CpuAccessibleBuffer::from_iter(
|
||||
self.queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
colors.into_iter(),
|
||||
)
|
||||
|
@ -62,7 +62,7 @@ fn main() {
|
||||
storage: true,
|
||||
color_attachment: true,
|
||||
transfer_dst: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -78,14 +78,20 @@ impl PixelsDrawPipeline {
|
||||
let (vertices, indices) = textured_quad(2.0, 2.0);
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::vertex_buffer(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::index_buffer(),
|
||||
BufferUsage {
|
||||
index_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
indices,
|
||||
)
|
||||
|
@ -110,10 +110,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics())
|
||||
@ -125,6 +125,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -277,9 +278,16 @@ fn main() {
|
||||
position: [0.5, -0.25],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let subpass = Subpass::from(render_pass, 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
@ -303,7 +311,10 @@ fn main() {
|
||||
|
||||
let buf = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
(0..1024 * 1024 * 4).map(|_| 0u8),
|
||||
)
|
||||
|
@ -92,10 +92,10 @@ fn main() {
|
||||
let (device, queue, surface_caps) = {
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| {
|
||||
@ -109,6 +109,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -155,7 +156,10 @@ fn main() {
|
||||
min_image_count: surface_caps.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_caps
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -185,9 +189,16 @@ fn main() {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mod vs {
|
||||
vulkano_shaders::shader! {
|
||||
@ -320,7 +331,10 @@ fn main() {
|
||||
min_image_count: surface_caps.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha,
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -39,7 +39,10 @@ pub struct GameOfLifeComputePipeline {
|
||||
fn rand_grid(compute_queue: &Arc<Queue>, size: [u32; 2]) -> Arc<CpuAccessibleBuffer<[u32]>> {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
compute_queue.device().clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
(0..(size[0] * size[1]))
|
||||
.map(|_| rand::thread_rng().gen_range(0u32..=1))
|
||||
@ -74,7 +77,7 @@ impl GameOfLifeComputePipeline {
|
||||
storage: true,
|
||||
color_attachment: true,
|
||||
transfer_dst: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -78,14 +78,20 @@ impl PixelsDrawPipeline {
|
||||
let (vertices, indices) = textured_quad(2.0, 2.0);
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::vertex_buffer(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices.into_iter(),
|
||||
)
|
||||
.unwrap();
|
||||
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
|
||||
gfx_queue.device().clone(),
|
||||
BufferUsage::index_buffer(),
|
||||
BufferUsage {
|
||||
index_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
indices.into_iter(),
|
||||
)
|
||||
|
@ -55,7 +55,7 @@ fn main() {
|
||||
InstanceCreateInfo {
|
||||
enabled_extensions: InstanceExtensions {
|
||||
khr_get_physical_device_properties2: true, // required to get multiview limits
|
||||
..InstanceExtensions::none()
|
||||
..InstanceExtensions::empty()
|
||||
},
|
||||
// Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK)
|
||||
enumerate_portability: true,
|
||||
@ -65,20 +65,20 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let features = Features {
|
||||
// enabling the `multiview` feature will use the `VK_KHR_multiview` extension on
|
||||
// Vulkan 1.0 and the device feature on Vulkan 1.1+
|
||||
multiview: true,
|
||||
..Features::none()
|
||||
..Features::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| {
|
||||
p.supported_extensions().is_superset_of(&device_extensions)
|
||||
p.supported_extensions().contains(&device_extensions)
|
||||
})
|
||||
.filter(|&p| {
|
||||
p.supported_features().is_superset_of(&features)
|
||||
p.supported_features().contains(&features)
|
||||
})
|
||||
.filter(|&p| {
|
||||
// This example renders to two layers of the framebuffer using the multiview
|
||||
@ -100,6 +100,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
// A real application should probably fall back to rendering the framebuffer layers
|
||||
// in multiple passes when multiview isn't supported.
|
||||
@ -135,9 +136,9 @@ fn main() {
|
||||
ImageUsage {
|
||||
transfer_src: true,
|
||||
color_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
ImageCreateFlags::none(),
|
||||
ImageCreateFlags::empty(),
|
||||
Some(queue_family),
|
||||
)
|
||||
.unwrap();
|
||||
@ -162,9 +163,16 @@ fn main() {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Note the `#extension GL_EXT_multiview : enable` that enables the multiview extension
|
||||
// for the shader and the use of `gl_ViewIndex` which contains a value based on which
|
||||
@ -268,7 +276,10 @@ fn main() {
|
||||
let create_buffer = || {
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
(0..image.dimensions().width() * image.dimensions().height() * 4).map(|_| 0u8),
|
||||
)
|
||||
|
@ -71,10 +71,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -86,6 +86,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -124,7 +125,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -190,9 +194,16 @@ fn main() {
|
||||
color: [0.0, 1.0, 0.0],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Create three buffer slices, one for each triangle.
|
||||
let triangle1 = vertex_buffer.slice::<Vertex>(0..3).unwrap();
|
||||
@ -381,7 +392,14 @@ fn main() {
|
||||
// Begin query 0, then draw the red triangle.
|
||||
// Enabling the `precise` bit would give exact numeric results. This needs
|
||||
// the `occlusion_query_precise` feature to be enabled on the device.
|
||||
.begin_query(query_pool.clone(), 0, QueryControlFlags { precise: false })
|
||||
.begin_query(
|
||||
query_pool.clone(),
|
||||
0,
|
||||
QueryControlFlags {
|
||||
precise: false,
|
||||
..QueryControlFlags::empty()
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
.bind_vertex_buffers(0, triangle1.clone())
|
||||
.draw(triangle1.len() as u32, 1, 0, 0)
|
||||
@ -390,7 +408,14 @@ fn main() {
|
||||
.end_query(query_pool.clone(), 0)
|
||||
.unwrap()
|
||||
// Begin query 1 for the cyan triangle.
|
||||
.begin_query(query_pool.clone(), 1, QueryControlFlags { precise: false })
|
||||
.begin_query(
|
||||
query_pool.clone(),
|
||||
1,
|
||||
QueryControlFlags {
|
||||
precise: false,
|
||||
..QueryControlFlags::empty()
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
.bind_vertex_buffers(0, triangle2.clone())
|
||||
.draw(triangle2.len() as u32, 1, 0, 0)
|
||||
@ -398,7 +423,14 @@ fn main() {
|
||||
.end_query(query_pool.clone(), 1)
|
||||
.unwrap()
|
||||
// Finally, query 2 for the green triangle.
|
||||
.begin_query(query_pool.clone(), 2, QueryControlFlags { precise: false })
|
||||
.begin_query(
|
||||
query_pool.clone(),
|
||||
2,
|
||||
QueryControlFlags {
|
||||
precise: false,
|
||||
..QueryControlFlags::empty()
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
.bind_vertex_buffers(0, triangle3.clone())
|
||||
.draw(triangle3.len() as u32, 1, 0, 0)
|
||||
@ -461,6 +493,7 @@ fn main() {
|
||||
// query in your `query_results` buffer for this. This element will
|
||||
// be filled with a zero/nonzero value indicating availability.
|
||||
with_availability: false,
|
||||
..QueryResultFlags::empty()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
@ -499,7 +532,7 @@ fn window_size_dependent_setup(
|
||||
ImageUsage {
|
||||
depth_stencil_attachment: true,
|
||||
transient_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
|
@ -57,10 +57,10 @@ fn main() {
|
||||
// Choose which physical device to use.
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -72,6 +72,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
|
@ -40,10 +40,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -55,6 +55,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -121,8 +122,16 @@ fn main() {
|
||||
|
||||
let data_buffer = {
|
||||
let data_iter = 0..65536u32;
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
|
||||
.unwrap()
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data_iter,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
|
@ -72,10 +72,10 @@ fn main() {
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
khr_push_descriptor: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -87,6 +87,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.expect("No suitable physical device found");
|
||||
|
||||
@ -125,7 +126,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -160,7 +164,10 @@ fn main() {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -87,10 +87,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -102,6 +102,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -140,7 +141,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -218,9 +222,16 @@ fn main() {
|
||||
color: [0.0, 0.0, 1.0],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// NOTE: We don't create any descriptor sets in this example, but you should
|
||||
// note that passing wrong types, providing sets at wrong indexes will cause
|
||||
|
@ -79,10 +79,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -94,6 +94,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -112,7 +113,7 @@ fn main() {
|
||||
shader_uniform_buffer_array_non_uniform_indexing: true,
|
||||
runtime_descriptor_array: true,
|
||||
descriptor_binding_variable_descriptor_count: true,
|
||||
..Features::none()
|
||||
..Features::empty()
|
||||
},
|
||||
queue_create_infos: vec![QueueCreateInfo::family(queue_family)],
|
||||
..Default::default()
|
||||
@ -139,7 +140,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -224,7 +228,10 @@ fn main() {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -40,10 +40,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -55,6 +55,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -116,7 +117,7 @@ fn main() {
|
||||
storage_buffer: true,
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::none()
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data_iter,
|
||||
|
@ -39,10 +39,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -54,6 +54,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -116,8 +117,16 @@ fn main() {
|
||||
|
||||
let data_buffer = {
|
||||
let data_iter = 0..65536u32;
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
|
||||
.unwrap()
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data_iter,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
|
@ -56,10 +56,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -71,6 +71,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -226,8 +227,16 @@ fn main() {
|
||||
// Preparing test data array `[0, 1, 2, 3....]`
|
||||
let data_buffer = {
|
||||
let data_iter = 0..65536u32;
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
|
||||
.unwrap()
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data_iter,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
// Loading the first shader, and creating a Pipeline for the shader
|
||||
|
@ -80,10 +80,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -95,6 +95,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -133,7 +134,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: [WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32],
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -323,7 +327,10 @@ fn main() {
|
||||
// Create a CPU accessible buffer initialized with the vertex data.
|
||||
let temporary_accessible_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::transfer_src(), // Specify this buffer will be used as a transfer source.
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
}, // Specify this buffer will be used as a transfer source.
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
@ -333,7 +340,14 @@ fn main() {
|
||||
let device_local_buffer = DeviceLocalBuffer::<[Vertex]>::array(
|
||||
device.clone(),
|
||||
PARTICLE_COUNT as vulkano::DeviceSize,
|
||||
BufferUsage::storage_buffer() | BufferUsage::vertex_buffer_transfer_dst(), // Specify use as a storage buffer, vertex buffer, and transfer destination.
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
} | BufferUsage {
|
||||
transfer_dst: true,
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
}, // Specify use as a storage buffer, vertex buffer, and transfer destination.
|
||||
device.active_queue_families(),
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -37,10 +37,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_storage_buffer_storage_class: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_compute())
|
||||
@ -52,6 +52,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -117,8 +118,16 @@ fn main() {
|
||||
|
||||
let data_buffer = {
|
||||
let data_iter = 0..65536u32;
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
|
||||
.unwrap()
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data_iter,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
||||
|
@ -71,10 +71,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -86,6 +86,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -125,7 +126,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -137,15 +141,44 @@ fn main() {
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, VERTICES)
|
||||
.unwrap();
|
||||
let normals_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, NORMALS).unwrap();
|
||||
let index_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, INDICES).unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
VERTICES,
|
||||
)
|
||||
.unwrap();
|
||||
let normals_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
NORMALS,
|
||||
)
|
||||
.unwrap();
|
||||
let index_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
index_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
INDICES,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(device.clone(), BufferUsage::all());
|
||||
let uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
uniform_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
);
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
@ -172,16 +172,16 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let features = Features {
|
||||
tessellation_shader: true,
|
||||
fill_mode_non_solid: true,
|
||||
..Features::none()
|
||||
..Features::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_features().is_superset_of(&features))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter(|&p| p.supported_features().contains(&features))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -193,6 +193,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -232,7 +233,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -280,9 +284,16 @@ fn main() {
|
||||
position: [-0.5, 0.9],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let tcs = tcs::load(device.clone()).unwrap();
|
||||
|
@ -76,10 +76,10 @@ fn main() {
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter(|&p| p.supported_extensions().contains(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false))
|
||||
@ -91,6 +91,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@ -129,7 +130,10 @@ fn main() {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
@ -164,7 +168,10 @@ fn main() {
|
||||
];
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
|
@ -101,7 +101,7 @@ fn main() {
|
||||
// `khr_swapchain` extension.
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
|
||||
// We then choose which physical device to use. First, we enumerate all the available physical
|
||||
@ -115,7 +115,7 @@ fn main() {
|
||||
// Some devices may not support the extensions or features that your application, or
|
||||
// report properties and limits that are not sufficient for your application. These
|
||||
// should be filtered out here.
|
||||
p.supported_extensions().is_superset_of(&device_extensions)
|
||||
p.supported_extensions().contains(&device_extensions)
|
||||
})
|
||||
.filter_map(|p| {
|
||||
// For each physical device, we try to find a suitable queue family that will execute
|
||||
@ -158,6 +158,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
}
|
||||
})
|
||||
.expect("No suitable physical device found");
|
||||
@ -188,7 +189,7 @@ fn main() {
|
||||
// higher, so we don't need to check for support.
|
||||
enabled_features: Features {
|
||||
dynamic_rendering: true,
|
||||
..Features::none()
|
||||
..Features::empty()
|
||||
},
|
||||
|
||||
// The list of queues that we are going to use. Here we only use one queue, from the
|
||||
@ -247,7 +248,10 @@ fn main() {
|
||||
// use that.
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
|
||||
// The alpha mode indicates how the alpha value of the final image will behave. For
|
||||
// example, you can choose whether the window will be opaque or transparent.
|
||||
@ -284,9 +288,16 @@ fn main() {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The next step is to create the shaders.
|
||||
//
|
||||
|
@ -95,7 +95,7 @@ fn main() {
|
||||
// `khr_swapchain` extension.
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
|
||||
// We then choose which physical device to use. First, we enumerate all the available physical
|
||||
@ -105,7 +105,7 @@ fn main() {
|
||||
// Some devices may not support the extensions or features that your application, or
|
||||
// report properties and limits that are not sufficient for your application. These
|
||||
// should be filtered out here.
|
||||
p.supported_extensions().is_superset_of(&device_extensions)
|
||||
p.supported_extensions().contains(&device_extensions)
|
||||
})
|
||||
.filter_map(|p| {
|
||||
// For each physical device, we try to find a suitable queue family that will execute
|
||||
@ -148,6 +148,7 @@ fn main() {
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
_ => 5,
|
||||
}
|
||||
})
|
||||
.expect("No suitable physical device found");
|
||||
@ -228,7 +229,10 @@ fn main() {
|
||||
// use that.
|
||||
image_extent: surface.window().inner_size().into(),
|
||||
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
|
||||
// The alpha mode indicates how the alpha value of the final image will behave. For
|
||||
// example, you can choose whether the window will be opaque or transparent.
|
||||
@ -265,9 +269,16 @@ fn main() {
|
||||
position: [0.25, -0.1],
|
||||
},
|
||||
];
|
||||
let vertex_buffer =
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, vertices)
|
||||
.unwrap();
|
||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
vertices,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// The next step is to create the shaders.
|
||||
//
|
||||
|
@ -173,6 +173,7 @@ fn write_descriptor_requirements(
|
||||
miss,
|
||||
intersection,
|
||||
callable,
|
||||
_ne: _,
|
||||
} = stages;
|
||||
|
||||
quote! {
|
||||
@ -189,6 +190,7 @@ fn write_descriptor_requirements(
|
||||
miss: #miss,
|
||||
intersection: #intersection,
|
||||
callable: #callable,
|
||||
..::vulkano::shader::ShaderStages::empty()
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -249,6 +251,7 @@ fn write_push_constant_requirements(
|
||||
miss,
|
||||
intersection,
|
||||
callable,
|
||||
_ne: _,
|
||||
} = stages;
|
||||
|
||||
quote! {
|
||||
@ -265,6 +268,7 @@ fn write_push_constant_requirements(
|
||||
miss: #miss,
|
||||
intersection: #intersection,
|
||||
callable: #callable,
|
||||
..::vulkano::shader::ShaderStages::empty()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -49,7 +49,7 @@ impl Default for VulkanoConfig {
|
||||
fn default() -> Self {
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
..DeviceExtensions::empty()
|
||||
};
|
||||
VulkanoConfig {
|
||||
instance_create_info: InstanceCreateInfo {
|
||||
@ -57,7 +57,7 @@ impl Default for VulkanoConfig {
|
||||
enabled_extensions: InstanceExtensions {
|
||||
#[cfg(target_os = "macos")]
|
||||
khr_portability_enumeration: true,
|
||||
..InstanceExtensions::none()
|
||||
..InstanceExtensions::empty()
|
||||
},
|
||||
#[cfg(target_os = "macos")]
|
||||
enumerate_portability: true,
|
||||
@ -65,7 +65,7 @@ impl Default for VulkanoConfig {
|
||||
},
|
||||
debug_create_info: None,
|
||||
device_filter_fn: Arc::new(move |p| {
|
||||
p.supported_extensions().is_superset_of(&device_extensions)
|
||||
p.supported_extensions().contains(&device_extensions)
|
||||
}),
|
||||
device_priority_fn: Arc::new(|p| match p.properties().device_type {
|
||||
PhysicalDeviceType::DiscreteGpu => 1,
|
||||
@ -73,10 +73,11 @@ impl Default for VulkanoConfig {
|
||||
PhysicalDeviceType::VirtualGpu => 3,
|
||||
PhysicalDeviceType::Cpu => 4,
|
||||
PhysicalDeviceType::Other => 5,
|
||||
_ => 6,
|
||||
}),
|
||||
print_device_name: false,
|
||||
device_extensions,
|
||||
device_features: Features::none(),
|
||||
device_features: Features::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +118,10 @@ impl VulkanoWindowRenderer {
|
||||
min_image_count: surface_capabilities.min_image_count,
|
||||
image_format,
|
||||
image_extent,
|
||||
image_usage: ImageUsage::color_attachment(),
|
||||
image_usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
composite_alpha: surface_capabilities
|
||||
.supported_composite_alpha
|
||||
.iter()
|
||||
|
@ -22,7 +22,7 @@ pub fn required_extensions(library: &VulkanLibrary) -> InstanceExtensions {
|
||||
mvk_macos_surface: true,
|
||||
khr_get_physical_device_properties2: true,
|
||||
khr_get_surface_capabilities2: true,
|
||||
..InstanceExtensions::none()
|
||||
..InstanceExtensions::empty()
|
||||
};
|
||||
|
||||
library.supported_extensions().intersection(&ideal)
|
||||
|
@ -285,19 +285,19 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
}
|
||||
});
|
||||
|
||||
let none_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
let empty_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
quote! {
|
||||
#name: false,
|
||||
}
|
||||
});
|
||||
|
||||
let not_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
let intersects_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
quote! {
|
||||
#name: !self.#name,
|
||||
(self.#name && other.#name)
|
||||
}
|
||||
});
|
||||
|
||||
let is_superset_of_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
let contains_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
quote! {
|
||||
(self.#name || !other.#name)
|
||||
}
|
||||
@ -321,6 +321,12 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
}
|
||||
});
|
||||
|
||||
let symmetric_difference_items = members.iter().map(|ExtensionsMember { name, .. }| {
|
||||
quote! {
|
||||
#name: self.#name ^ other.#name,
|
||||
}
|
||||
});
|
||||
|
||||
let debug_items = members.iter().map(|ExtensionsMember { name, raw, .. }| {
|
||||
quote! {
|
||||
if self.#name {
|
||||
@ -358,38 +364,47 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
impl Default for #struct_name {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::none()
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl #struct_name {
|
||||
/// Returns an `Extensions` object with all members set to `false`.
|
||||
/// Returns an `Extensions` object with none of the members set.
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
#(#empty_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an `Extensions` object with none of the members set.
|
||||
#[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
|
||||
#[inline]
|
||||
pub const fn none() -> Self {
|
||||
Self {
|
||||
#(#none_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
Self::empty()
|
||||
}
|
||||
|
||||
/// Returns true if `self` is a superset of the parameter.
|
||||
///
|
||||
/// That is, for each extension of the parameter that is true, the corresponding value
|
||||
/// in self is true as well.
|
||||
pub fn is_superset_of(&self, other: &Self) -> bool {
|
||||
#(#is_superset_of_items)&&*
|
||||
}
|
||||
|
||||
/// Returns the not of this list.
|
||||
/// Returns whether any members are set in both `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn not_const(&self) -> Self {
|
||||
Self {
|
||||
#(#not_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
pub const fn intersects(&self, other: &Self) -> bool {
|
||||
#(#intersects_items)||*
|
||||
}
|
||||
|
||||
/// Returns the union of this list and another list.
|
||||
/// Returns whether all members in `other` are set in `self`.
|
||||
#[inline]
|
||||
pub const fn contains(&self, other: &Self) -> bool {
|
||||
#(#contains_items)&&*
|
||||
}
|
||||
|
||||
/// Returns whether all members in `other` are set in `self`.
|
||||
#[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
|
||||
#[inline]
|
||||
pub const fn is_superset_of(&self, other: &Self) -> bool {
|
||||
self.contains(other)
|
||||
}
|
||||
|
||||
/// Returns the union of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn union(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
@ -398,7 +413,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the intersection of this list and another list.
|
||||
/// Returns the intersection of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersection(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
@ -407,7 +422,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the difference of another list from this list.
|
||||
/// Returns `self` without the members set in `other`.
|
||||
#[inline]
|
||||
pub const fn difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
@ -415,25 +430,28 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for #struct_name {
|
||||
type Output = #struct_name;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
self.not_const()
|
||||
/// Returns the members set in `self` or `other`, but not both.
|
||||
#[inline]
|
||||
pub const fn symmetric_difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
#(#symmetric_difference_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAnd for #struct_name {
|
||||
type Output = #struct_name;
|
||||
|
||||
#[inline]
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
self.union(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAndAssign for #struct_name {
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
*self = self.union(&rhs);
|
||||
}
|
||||
@ -442,26 +460,46 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
impl BitOr for #struct_name {
|
||||
type Output = #struct_name;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
self.intersection(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for #struct_name {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = self.intersection(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl BitXor for #struct_name {
|
||||
type Output = #struct_name;
|
||||
|
||||
#[inline]
|
||||
fn bitxor(self, rhs: Self) -> Self::Output {
|
||||
self.symmetric_difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitXorAssign for #struct_name {
|
||||
#[inline]
|
||||
fn bitxor_assign(&mut self, rhs: Self) {
|
||||
*self = self.symmetric_difference(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for #struct_name {
|
||||
type Output = #struct_name;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for #struct_name {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = self.difference(&rhs);
|
||||
}
|
||||
@ -481,7 +519,7 @@ fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) ->
|
||||
|
||||
impl<'a, I> From<I> for #struct_name where I: IntoIterator<Item = &'a CStr> {
|
||||
fn from(names: I) -> Self {
|
||||
let mut extensions = Self::none();
|
||||
let mut extensions = Self::empty();
|
||||
for name in names {
|
||||
match name.to_bytes() {
|
||||
#(#from_cstr_for_extensions_items)*
|
||||
|
@ -161,7 +161,7 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
},
|
||||
);
|
||||
|
||||
let none_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
let empty_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
quote! {
|
||||
#name: false,
|
||||
}
|
||||
@ -173,15 +173,15 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
}
|
||||
});
|
||||
|
||||
let is_superset_of_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
let intersects_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
quote! {
|
||||
(self.#name || !other.#name)
|
||||
(self.#name && other.#name)
|
||||
}
|
||||
});
|
||||
|
||||
let not_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
let contains_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
quote! {
|
||||
#name: !self.#name,
|
||||
(self.#name || !other.#name)
|
||||
}
|
||||
});
|
||||
|
||||
@ -203,6 +203,12 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
}
|
||||
});
|
||||
|
||||
let symmetric_difference_items = members.iter().map(|FeaturesMember { name, .. }| {
|
||||
quote! {
|
||||
#name: self.#name ^ other.#name,
|
||||
}
|
||||
});
|
||||
|
||||
let debug_items = members.iter().map(|FeaturesMember { name, raw, .. }| {
|
||||
quote! {
|
||||
if self.#name {
|
||||
@ -291,13 +297,13 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
/// # let physical_device: vulkano::device::physical::PhysicalDevice = return;
|
||||
/// let minimal_features = Features {
|
||||
/// geometry_shader: true,
|
||||
/// .. Features::none()
|
||||
/// .. Features::empty()
|
||||
/// };
|
||||
///
|
||||
/// let optimal_features = vulkano::device::Features {
|
||||
/// geometry_shader: true,
|
||||
/// tessellation_shader: true,
|
||||
/// .. Features::none()
|
||||
/// .. Features::empty()
|
||||
/// };
|
||||
///
|
||||
/// if !physical_device.supported_features().is_superset_of(&minimal_features) {
|
||||
@ -317,7 +323,7 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
impl Default for Features {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::none()
|
||||
Self::empty()
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,18 +339,23 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Builds a `Features` object with all values to false.
|
||||
pub const fn none() -> Self {
|
||||
Features {
|
||||
#(#none_items)*
|
||||
/// Returns an `Features` object with none of the members set.
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
#(#empty_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `Features` object with all values to true.
|
||||
///
|
||||
/// > **Note**: This function is used for testing purposes, and is probably useless in
|
||||
/// > a real code.
|
||||
/// Returns an `Features` object with none of the members set.
|
||||
#[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
|
||||
#[inline]
|
||||
pub const fn none() -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
|
||||
/// Returns a `Features` object with all of the members set.
|
||||
#[cfg(test)]
|
||||
pub(crate) const fn all() -> Features {
|
||||
Features {
|
||||
@ -353,23 +364,26 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if `self` is a superset of the parameter.
|
||||
///
|
||||
/// That is, for each feature of the parameter that is true, the corresponding value
|
||||
/// in self is true as well.
|
||||
/// Returns whether any members are set in both `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersects(&self, other: &Self) -> bool {
|
||||
#(#intersects_items)||*
|
||||
}
|
||||
|
||||
/// Returns whether all members in `other` are set in `self`.
|
||||
#[inline]
|
||||
pub const fn contains(&self, other: &Self) -> bool {
|
||||
#(#contains_items)&&*
|
||||
}
|
||||
|
||||
/// Returns whether all members in `other` are set in `self`.
|
||||
#[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
|
||||
#[inline]
|
||||
pub const fn is_superset_of(&self, other: &Self) -> bool {
|
||||
#(#is_superset_of_items)&&*
|
||||
self.contains(other)
|
||||
}
|
||||
|
||||
/// Returns the not of this list.
|
||||
pub const fn not_const(self) -> Self {
|
||||
Self {
|
||||
#(#not_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the union of this list and another list.
|
||||
/// Returns the union of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn union(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
@ -378,10 +392,8 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `Features` that is the intersection of `self` and another `Features`
|
||||
/// object.
|
||||
///
|
||||
/// The result's field will be true if it is also true in both `self` and `other`.
|
||||
/// Returns the intersection of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersection(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
#(#intersection_items)*
|
||||
@ -389,62 +401,84 @@ fn features_output(members: &[FeaturesMember]) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `Features` that is the difference of another `Features` object from `self`.
|
||||
///
|
||||
/// The result's field will be true if it is true in `self` but not `other`.
|
||||
/// Returns `self` without the members set in `other`.
|
||||
#[inline]
|
||||
pub const fn difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
#(#difference_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for Features {
|
||||
type Output = Features;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
self.not_const()
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for Features {
|
||||
type Output = Features;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
self.union(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for Features {
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = self.union(&rhs);
|
||||
/// Returns the members set in `self` or `other`, but not both.
|
||||
#[inline]
|
||||
pub const fn symmetric_difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
#(#symmetric_difference_items)*
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAnd for Features {
|
||||
type Output = Features;
|
||||
|
||||
#[inline]
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
self.intersection(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAndAssign for Features {
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
*self = self.intersection(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for Features {
|
||||
type Output = Features;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
self.union(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOrAssign for Features {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = self.union(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl BitXor for Features {
|
||||
type Output = Features;
|
||||
|
||||
#[inline]
|
||||
fn bitxor(self, rhs: Self) -> Self::Output {
|
||||
self.symmetric_difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl BitXorAssign for Features {
|
||||
#[inline]
|
||||
fn bitxor_assign(&mut self, rhs: Self) {
|
||||
*self = self.symmetric_difference(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Features {
|
||||
type Output = Features;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for Features {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = self.difference(&rhs);
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ fn formats_output(members: &[FormatMember]) -> TokenStream {
|
||||
plane0: matches!(self, #(Format::#aspects_plane0_items)|* ),
|
||||
plane1: matches!(self, #(Format::#aspects_plane1_items)|* ),
|
||||
plane2: matches!(self, #(Format::#aspects_plane2_items)|* ),
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -626,10 +626,26 @@ mod tests {
|
||||
const EMPTY: [i32; 0] = [];
|
||||
|
||||
assert_should_panic!({
|
||||
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, EMPTY)
|
||||
.unwrap();
|
||||
CpuAccessibleBuffer::from_iter(device, BufferUsage::all(), false, EMPTY.into_iter())
|
||||
.unwrap();
|
||||
CpuAccessibleBuffer::from_data(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
EMPTY,
|
||||
)
|
||||
.unwrap();
|
||||
CpuAccessibleBuffer::from_iter(
|
||||
device,
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
EMPTY.into_iter(),
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -217,7 +217,13 @@ where
|
||||
/// - Panics if `T` has zero size.
|
||||
#[inline]
|
||||
pub fn upload(device: Arc<Device>) -> CpuBufferPool<T> {
|
||||
CpuBufferPool::new(device, BufferUsage::transfer_src())
|
||||
CpuBufferPool::new(
|
||||
device,
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds a `CpuBufferPool` meant for simple downloads.
|
||||
@ -230,7 +236,13 @@ where
|
||||
/// - Panics if `T` has zero size.
|
||||
#[inline]
|
||||
pub fn download(device: Arc<Device>) -> CpuBufferPool<T> {
|
||||
CpuBufferPool::new(device, BufferUsage::transfer_dst())
|
||||
CpuBufferPool::new(
|
||||
device,
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds a `CpuBufferPool` meant for usage as a uniform buffer.
|
||||
@ -243,7 +255,13 @@ where
|
||||
/// - Panics if `T` has zero size.
|
||||
#[inline]
|
||||
pub fn uniform_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
|
||||
CpuBufferPool::new(device, BufferUsage::uniform_buffer())
|
||||
CpuBufferPool::new(
|
||||
device,
|
||||
BufferUsage {
|
||||
uniform_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds a `CpuBufferPool` meant for usage as a vertex buffer.
|
||||
@ -256,7 +274,13 @@ where
|
||||
/// - Panics if `T` has zero size.
|
||||
#[inline]
|
||||
pub fn vertex_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
|
||||
CpuBufferPool::new(device, BufferUsage::vertex_buffer())
|
||||
CpuBufferPool::new(
|
||||
device,
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds a `CpuBufferPool` meant for usage as a indirect buffer.
|
||||
@ -269,7 +293,13 @@ where
|
||||
/// - Panics if `T` has zero size.
|
||||
#[inline]
|
||||
pub fn indirect_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
|
||||
CpuBufferPool::new(device, BufferUsage::indirect_buffer())
|
||||
CpuBufferPool::new(
|
||||
device,
|
||||
BufferUsage {
|
||||
indirect_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ use std::{
|
||||
/// // Create a CPU accessible buffer initialized with the data.
|
||||
/// let temporary_accessible_buffer = CpuAccessibleBuffer::from_iter(
|
||||
/// device.clone(),
|
||||
/// BufferUsage::transfer_src(), // Specify this buffer will be used as a transfer source.
|
||||
/// BufferUsage { transfer_src: true, ..BufferUsage::empty() }, // Specify this buffer will be used as a transfer source.
|
||||
/// false,
|
||||
/// data,
|
||||
/// )
|
||||
@ -94,7 +94,11 @@ use std::{
|
||||
/// let device_local_buffer = DeviceLocalBuffer::<[f32]>::array(
|
||||
/// device.clone(),
|
||||
/// 10_000 as vulkano::DeviceSize,
|
||||
/// BufferUsage::storage_buffer() | BufferUsage::transfer_dst(), // Specify use as a storage buffer and transfer destination.
|
||||
/// BufferUsage {
|
||||
/// storage_buffer: true,
|
||||
/// transfer_dst: true,
|
||||
/// ..BufferUsage::empty()
|
||||
/// }, // Specify use as a storage buffer and transfer destination.
|
||||
/// device.active_queue_families(),
|
||||
/// )
|
||||
/// .unwrap();
|
||||
@ -250,7 +254,10 @@ where
|
||||
> {
|
||||
let source = CpuAccessibleBuffer::from_data(
|
||||
queue.device().clone(),
|
||||
BufferUsage::transfer_src(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data,
|
||||
)?;
|
||||
@ -283,7 +290,10 @@ where
|
||||
{
|
||||
let source = CpuAccessibleBuffer::from_iter(
|
||||
queue.device().clone(),
|
||||
BufferUsage::transfer_src(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
data,
|
||||
)?;
|
||||
@ -613,11 +623,26 @@ mod tests {
|
||||
fn from_data_working() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
let (buffer, _) =
|
||||
DeviceLocalBuffer::from_data(12u32, BufferUsage::all(), queue.clone()).unwrap();
|
||||
let (buffer, _) = DeviceLocalBuffer::from_data(
|
||||
12u32,
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let destination =
|
||||
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
|
||||
let destination = CpuAccessibleBuffer::from_data(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut cbb = AutoCommandBufferBuilder::primary(
|
||||
device,
|
||||
@ -645,14 +670,20 @@ mod tests {
|
||||
|
||||
let (buffer, _) = DeviceLocalBuffer::from_iter(
|
||||
(0..512u32).map(|n| n * 2),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let destination = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
(0..512).map(|_| 0u32),
|
||||
)
|
||||
@ -686,7 +717,15 @@ mod tests {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
assert_should_panic!({
|
||||
DeviceLocalBuffer::from_data((), BufferUsage::all(), queue.clone()).unwrap();
|
||||
DeviceLocalBuffer::from_data(
|
||||
(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -193,7 +193,7 @@ impl ExternalBufferInfo {
|
||||
pub fn handle_type(handle_type: ExternalMemoryHandleType) -> Self {
|
||||
Self {
|
||||
handle_type,
|
||||
usage: BufferUsage::none(),
|
||||
usage: BufferUsage::empty(),
|
||||
sparse: None,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
macros::{vulkan_bitflags, ExtensionNotEnabled},
|
||||
memory::{DeviceMemory, DeviceMemoryAllocationError, MemoryRequirements},
|
||||
range_map::RangeMap,
|
||||
sync::{AccessError, CurrentAccess, Sharing},
|
||||
@ -84,8 +85,11 @@ impl UnsafeBuffer {
|
||||
// VUID-VkBufferCreateInfo-size-00912
|
||||
assert!(size != 0);
|
||||
|
||||
// VUID-VkBufferCreateInfo-usage-parameter
|
||||
usage.validate(&device)?;
|
||||
|
||||
// VUID-VkBufferCreateInfo-usage-requiredbitmask
|
||||
assert!(usage != BufferUsage::none());
|
||||
assert!(!usage.is_empty());
|
||||
|
||||
let mut flags = ash::vk::BufferCreateFlags::empty();
|
||||
|
||||
@ -433,7 +437,7 @@ pub struct UnsafeBufferCreateInfo {
|
||||
|
||||
/// How the buffer is going to be used.
|
||||
///
|
||||
/// The default value is [`BufferUsage::none()`], which must be overridden.
|
||||
/// The default value is [`BufferUsage::empty()`], which must be overridden.
|
||||
pub usage: BufferUsage,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
@ -446,7 +450,7 @@ impl Default for UnsafeBufferCreateInfo {
|
||||
sharing: Sharing::Exclusive,
|
||||
size: 0,
|
||||
sparse: None,
|
||||
usage: BufferUsage::none(),
|
||||
usage: BufferUsage::empty(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -531,48 +535,26 @@ impl From<VulkanError> for BufferCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
/// The level of sparse binding that a buffer should be created with.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SparseLevel {
|
||||
pub sparse_residency: bool,
|
||||
pub sparse_aliased: bool,
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for SparseLevel {
|
||||
impl From<ExtensionNotEnabled> for BufferCreationError {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sparse_residency: false,
|
||||
sparse_aliased: false,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SparseLevel {
|
||||
#[inline]
|
||||
pub fn none() -> SparseLevel {
|
||||
SparseLevel {
|
||||
sparse_residency: false,
|
||||
sparse_aliased: false,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
vulkan_bitflags! {
|
||||
/// The level of sparse binding that a buffer should be created with.
|
||||
#[non_exhaustive]
|
||||
SparseLevel = BufferCreateFlags(u32);
|
||||
|
||||
impl From<SparseLevel> for ash::vk::BufferCreateFlags {
|
||||
#[inline]
|
||||
fn from(val: SparseLevel) -> Self {
|
||||
let mut result = ash::vk::BufferCreateFlags::SPARSE_BINDING;
|
||||
if val.sparse_residency {
|
||||
result |= ash::vk::BufferCreateFlags::SPARSE_RESIDENCY;
|
||||
}
|
||||
if val.sparse_aliased {
|
||||
result |= ash::vk::BufferCreateFlags::SPARSE_ALIASED;
|
||||
}
|
||||
result
|
||||
}
|
||||
// TODO: document
|
||||
sparse_residency = SPARSE_ALIASED,
|
||||
|
||||
// TODO: document
|
||||
sparse_aliased = SPARSE_ALIASED,
|
||||
}
|
||||
|
||||
/// The current state of a buffer.
|
||||
@ -798,7 +780,10 @@ mod tests {
|
||||
device.clone(),
|
||||
UnsafeBufferCreateInfo {
|
||||
size: 128,
|
||||
usage: BufferUsage::all(),
|
||||
usage: BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@ -817,8 +802,11 @@ mod tests {
|
||||
device,
|
||||
UnsafeBufferCreateInfo {
|
||||
size: 128,
|
||||
sparse: Some(SparseLevel::none()),
|
||||
usage: BufferUsage::all(),
|
||||
sparse: Some(SparseLevel::empty()),
|
||||
usage: BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
) {
|
||||
@ -842,7 +830,10 @@ mod tests {
|
||||
sparse_aliased: false,
|
||||
..Default::default()
|
||||
}),
|
||||
usage: BufferUsage::all(),
|
||||
usage: BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
) {
|
||||
@ -866,7 +857,10 @@ mod tests {
|
||||
sparse_aliased: true,
|
||||
..Default::default()
|
||||
}),
|
||||
usage: BufferUsage::all(),
|
||||
usage: BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
) {
|
||||
@ -887,7 +881,10 @@ mod tests {
|
||||
device,
|
||||
UnsafeBufferCreateInfo {
|
||||
size: 0,
|
||||
usage: BufferUsage::all(),
|
||||
usage: BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
@ -86,7 +86,7 @@ pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
|
||||
}
|
||||
|
||||
// VUID-VkBufferDeviceAddressInfo-buffer-02601
|
||||
if !inner.buffer.usage().device_address {
|
||||
if !inner.buffer.usage().shader_device_address {
|
||||
return Err(BufferDeviceAddressError::BufferMissingUsage);
|
||||
}
|
||||
|
||||
|
@ -7,255 +7,97 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::ops::BitOr;
|
||||
use crate::macros::vulkan_bitflags;
|
||||
|
||||
/// Describes how a buffer is going to be used. This is **not** just an optimization.
|
||||
///
|
||||
/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
|
||||
///
|
||||
/// Some methods are provided to build `BufferUsage` structs for some common situations. However
|
||||
/// there is no restriction in the combination of BufferUsages that can be enabled.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct BufferUsage {
|
||||
pub transfer_src: bool,
|
||||
pub transfer_dst: bool,
|
||||
pub uniform_texel_buffer: bool,
|
||||
pub storage_texel_buffer: bool,
|
||||
pub uniform_buffer: bool,
|
||||
pub storage_buffer: bool,
|
||||
pub index_buffer: bool,
|
||||
pub vertex_buffer: bool,
|
||||
pub indirect_buffer: bool,
|
||||
pub device_address: bool,
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for BufferUsage {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
uniform_texel_buffer: false,
|
||||
storage_texel_buffer: false,
|
||||
uniform_buffer: false,
|
||||
storage_buffer: false,
|
||||
index_buffer: false,
|
||||
vertex_buffer: false,
|
||||
indirect_buffer: false,
|
||||
device_address: false,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BufferUsage {
|
||||
/// Builds a `BufferUsage` with all values set to false.
|
||||
#[inline]
|
||||
pub const fn none() -> BufferUsage {
|
||||
BufferUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
uniform_texel_buffer: false,
|
||||
storage_texel_buffer: false,
|
||||
uniform_buffer: false,
|
||||
storage_buffer: false,
|
||||
index_buffer: false,
|
||||
vertex_buffer: false,
|
||||
indirect_buffer: false,
|
||||
device_address: false,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with all values set to true. Can be used for quick prototyping.
|
||||
#[inline]
|
||||
pub const fn all() -> BufferUsage {
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
uniform_texel_buffer: true,
|
||||
storage_texel_buffer: true,
|
||||
uniform_buffer: true,
|
||||
storage_buffer: true,
|
||||
index_buffer: true,
|
||||
vertex_buffer: true,
|
||||
indirect_buffer: true,
|
||||
device_address: true,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `transfer_src` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn transfer_src() -> BufferUsage {
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `transfer_dst` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn transfer_dst() -> BufferUsage {
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `vertex_buffer` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn vertex_buffer() -> BufferUsage {
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `vertex_buffer` and `transfer_dst` set to true and the rest
|
||||
/// to false.
|
||||
#[inline]
|
||||
pub const fn vertex_buffer_transfer_dst() -> BufferUsage {
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `index_buffer` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn index_buffer() -> BufferUsage {
|
||||
BufferUsage {
|
||||
index_buffer: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `index_buffer` and `transfer_dst` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn index_buffer_transfer_dst() -> BufferUsage {
|
||||
BufferUsage {
|
||||
index_buffer: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `uniform_buffer` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn uniform_buffer() -> BufferUsage {
|
||||
BufferUsage {
|
||||
uniform_buffer: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with only `storage_buffer` set, while rest are not
|
||||
#[inline]
|
||||
pub const fn storage_buffer() -> BufferUsage {
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `uniform_buffer` and `transfer_dst` set to true and the rest
|
||||
/// to false.
|
||||
#[inline]
|
||||
pub const fn uniform_buffer_transfer_dst() -> BufferUsage {
|
||||
BufferUsage {
|
||||
uniform_buffer: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `indirect_buffer` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn indirect_buffer() -> BufferUsage {
|
||||
BufferUsage {
|
||||
indirect_buffer: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `indirect_buffer` and `transfer_dst` set to true and the rest
|
||||
/// to false.
|
||||
#[inline]
|
||||
pub const fn indirect_buffer_transfer_dst() -> BufferUsage {
|
||||
BufferUsage {
|
||||
indirect_buffer: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `BufferUsage` with `device_address` set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn device_address() -> BufferUsage {
|
||||
BufferUsage {
|
||||
device_address: true,
|
||||
..BufferUsage::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BufferUsage> for ash::vk::BufferUsageFlags {
|
||||
fn from(val: BufferUsage) -> Self {
|
||||
let mut result = ash::vk::BufferUsageFlags::empty();
|
||||
if val.transfer_src {
|
||||
result |= ash::vk::BufferUsageFlags::TRANSFER_SRC;
|
||||
}
|
||||
if val.transfer_dst {
|
||||
result |= ash::vk::BufferUsageFlags::TRANSFER_DST;
|
||||
}
|
||||
if val.uniform_texel_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::UNIFORM_TEXEL_BUFFER;
|
||||
}
|
||||
if val.storage_texel_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::STORAGE_TEXEL_BUFFER;
|
||||
}
|
||||
if val.uniform_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::UNIFORM_BUFFER;
|
||||
}
|
||||
if val.storage_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::STORAGE_BUFFER;
|
||||
}
|
||||
if val.index_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::INDEX_BUFFER;
|
||||
}
|
||||
if val.vertex_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::VERTEX_BUFFER;
|
||||
}
|
||||
if val.indirect_buffer {
|
||||
result |= ash::vk::BufferUsageFlags::INDIRECT_BUFFER;
|
||||
}
|
||||
if val.device_address {
|
||||
result |= ash::vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for BufferUsage {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
BufferUsage {
|
||||
transfer_src: self.transfer_src || rhs.transfer_src,
|
||||
transfer_dst: self.transfer_dst || rhs.transfer_dst,
|
||||
uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
|
||||
storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
|
||||
uniform_buffer: self.uniform_buffer || rhs.uniform_buffer,
|
||||
storage_buffer: self.storage_buffer || rhs.storage_buffer,
|
||||
index_buffer: self.index_buffer || rhs.index_buffer,
|
||||
vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
|
||||
indirect_buffer: self.indirect_buffer || rhs.indirect_buffer,
|
||||
device_address: self.device_address || rhs.device_address,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
vulkan_bitflags! {
|
||||
/// Describes how a buffer is going to be used. This is **not** just an optimization.
|
||||
///
|
||||
/// If you try to use a buffer in a way that you didn't declare, an error will be returned.
|
||||
#[non_exhaustive]
|
||||
BufferUsage = BufferUsageFlags(u32);
|
||||
|
||||
/// The buffer can be used as a source for transfer, blit, resolve and clear commands.
|
||||
transfer_src = TRANSFER_SRC,
|
||||
|
||||
/// The buffer can be used as a destination for transfer, blit, resolve and clear commands.
|
||||
transfer_dst = TRANSFER_DST,
|
||||
|
||||
/// The buffer can be used as a uniform texel buffer in a descriptor set.
|
||||
uniform_texel_buffer = UNIFORM_TEXEL_BUFFER,
|
||||
|
||||
/// The buffer can be used as a storage texel buffer in a descriptor set.
|
||||
storage_texel_buffer = STORAGE_TEXEL_BUFFER,
|
||||
|
||||
/// The buffer can be used as a uniform buffer in a descriptor set.
|
||||
uniform_buffer = UNIFORM_BUFFER,
|
||||
|
||||
/// The buffer can be used as a storage buffer in a descriptor set.
|
||||
storage_buffer = STORAGE_BUFFER,
|
||||
|
||||
/// The buffer can be used as an index buffer.
|
||||
index_buffer = INDEX_BUFFER,
|
||||
|
||||
/// The buffer can be used as a vertex or instance buffer.
|
||||
vertex_buffer = VERTEX_BUFFER,
|
||||
|
||||
/// The buffer can be used as an indirect buffer.
|
||||
indirect_buffer = INDIRECT_BUFFER,
|
||||
|
||||
/// The buffer's device address can be retrieved.
|
||||
shader_device_address = SHADER_DEVICE_ADDRESS {
|
||||
api_version: V1_2,
|
||||
extensions: [khr_buffer_device_address, ext_buffer_device_address],
|
||||
},
|
||||
|
||||
/*
|
||||
// TODO: document
|
||||
video_decode_src = VIDEO_DECODE_SRC_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
video_decode_dst = VIDEO_DECODE_DST_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
transform_feedback_buffer = TRANSFORM_FEEDBACK_BUFFER_EXT {
|
||||
extensions: [ext_transform_feedback],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
transform_feedback_counter_buffer = TRANSFORM_FEEDBACK_COUNTER_BUFFER_EXT {
|
||||
extensions: [ext_transform_feedback],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
conditional_rendering = CONDITIONAL_RENDERING_EXT {
|
||||
extensions: [ext_conditional_rendering],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
acceleration_structure_build_input_read_only = ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR {
|
||||
extensions: [khr_acceleration_structure],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
acceleration_structure_storage = ACCELERATION_STRUCTURE_STORAGE_KHR {
|
||||
extensions: [khr_acceleration_structure],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
shader_binding_table = SHADER_BINDING_TABLE_KHR {
|
||||
extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
video_encode_dst = VIDEO_ENCODE_DST_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
video_encode_src = VIDEO_ENCODE_SRC_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
//! # let queue: Arc<vulkano::device::Queue> = return;
|
||||
//! let usage = BufferUsage {
|
||||
//! storage_texel_buffer: true,
|
||||
//! .. BufferUsage::none()
|
||||
//! .. BufferUsage::empty()
|
||||
//! };
|
||||
//!
|
||||
//! let (buffer, _future) = DeviceLocalBuffer::<[u32]>::from_iter((0..128).map(|n| n), usage,
|
||||
@ -479,7 +479,7 @@ mod tests {
|
||||
|
||||
let usage = BufferUsage {
|
||||
uniform_texel_buffer: true,
|
||||
..BufferUsage::none()
|
||||
..BufferUsage::empty()
|
||||
};
|
||||
|
||||
let (buffer, _) =
|
||||
@ -502,7 +502,7 @@ mod tests {
|
||||
|
||||
let usage = BufferUsage {
|
||||
storage_texel_buffer: true,
|
||||
..BufferUsage::none()
|
||||
..BufferUsage::empty()
|
||||
};
|
||||
|
||||
let (buffer, _) =
|
||||
@ -525,7 +525,7 @@ mod tests {
|
||||
|
||||
let usage = BufferUsage {
|
||||
storage_texel_buffer: true,
|
||||
..BufferUsage::none()
|
||||
..BufferUsage::empty()
|
||||
};
|
||||
|
||||
let (buffer, _) =
|
||||
@ -547,7 +547,7 @@ mod tests {
|
||||
|
||||
let (buffer, _) = DeviceLocalBuffer::<[[u8; 4]]>::from_iter(
|
||||
(0..128).map(|_| [0; 4]),
|
||||
BufferUsage::none(),
|
||||
BufferUsage::empty(),
|
||||
queue,
|
||||
)
|
||||
.unwrap();
|
||||
@ -571,7 +571,7 @@ mod tests {
|
||||
let usage = BufferUsage {
|
||||
uniform_texel_buffer: true,
|
||||
storage_texel_buffer: true,
|
||||
..BufferUsage::none()
|
||||
..BufferUsage::empty()
|
||||
};
|
||||
|
||||
let (buffer, _) =
|
||||
|
@ -24,6 +24,7 @@ use crate::{
|
||||
device::{physical::QueueFamily, Device, DeviceOwned, Queue},
|
||||
format::Format,
|
||||
image::{sys::UnsafeImage, ImageAccess, ImageLayout, ImageSubresourceRange},
|
||||
macros::ExtensionNotEnabled,
|
||||
query::{QueryControlFlags, QueryType},
|
||||
render_pass::{Framebuffer, Subpass},
|
||||
sync::{AccessCheckError, AccessFlags, GpuFuture, PipelineMemoryAccess, PipelineStages},
|
||||
@ -432,6 +433,9 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
|
||||
}
|
||||
|
||||
if let Some(control_flags) = occlusion_query {
|
||||
// VUID-VkCommandBufferInheritanceInfo-queryFlags-00057
|
||||
control_flags.validate(device)?;
|
||||
|
||||
// VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056
|
||||
// VUID-VkCommandBufferInheritanceInfo-queryFlags-02788
|
||||
if !device.enabled_features().inherited_queries {
|
||||
@ -450,6 +454,9 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
|
||||
}
|
||||
}
|
||||
|
||||
// VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789
|
||||
query_statistics_flags.validate(device)?;
|
||||
|
||||
// VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058
|
||||
if query_statistics_flags.count() > 0
|
||||
&& !device.enabled_features().pipeline_statistics_query
|
||||
@ -476,6 +483,10 @@ pub enum CommandBufferBeginError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
@ -516,6 +527,9 @@ impl Display for CommandBufferBeginError {
|
||||
match *self {
|
||||
Self::OomError(_) => write!(f, "not enough memory available"),
|
||||
|
||||
Self::ExtensionNotEnabled { extension, reason } => {
|
||||
write!(f, "the extension {} must be enabled: {}", extension, reason)
|
||||
}
|
||||
Self::FeatureNotEnabled { feature, reason } => {
|
||||
write!(f, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
@ -554,6 +568,16 @@ impl From<OomError> for CommandBufferBeginError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for CommandBufferBeginError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
|
||||
where
|
||||
P: CommandPoolBuilderAlloc,
|
||||
@ -961,7 +985,10 @@ mod tests {
|
||||
|
||||
let source = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
true,
|
||||
[1_u32, 2].iter().copied(),
|
||||
)
|
||||
@ -969,7 +996,10 @@ mod tests {
|
||||
|
||||
let destination = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
true,
|
||||
[0_u32, 10, 20, 3, 4].iter().copied(),
|
||||
)
|
||||
@ -1086,7 +1116,11 @@ mod tests {
|
||||
|
||||
let source = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
true,
|
||||
[0_u32, 1, 2, 3].iter().copied(),
|
||||
)
|
||||
@ -1132,7 +1166,11 @@ mod tests {
|
||||
|
||||
let source = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
true,
|
||||
[0_u32, 1, 2, 3].iter().copied(),
|
||||
)
|
||||
|
@ -21,6 +21,7 @@ use crate::{
|
||||
DescriptorWriteInfo, WriteDescriptorSet,
|
||||
},
|
||||
device::DeviceOwned,
|
||||
macros::ExtensionNotEnabled,
|
||||
pipeline::{
|
||||
graphics::{
|
||||
input_assembly::{Index, IndexType},
|
||||
@ -90,6 +91,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
first_set: u32,
|
||||
descriptor_sets: &[DescriptorSetWithOffsets],
|
||||
) -> Result<(), BindPushError> {
|
||||
// VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter
|
||||
pipeline_bind_point.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool
|
||||
// VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361
|
||||
match pipeline_bind_point {
|
||||
@ -533,10 +537,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
if !self.device().enabled_extensions().khr_push_descriptor {
|
||||
return Err(BindPushError::ExtensionNotEnabled {
|
||||
extension: "khr_push_descriptor",
|
||||
reason: "called validate_push_descriptor_set",
|
||||
reason: "called push_descriptor_set",
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter
|
||||
pipeline_bind_point.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool
|
||||
// VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363
|
||||
match pipeline_bind_point {
|
||||
@ -1059,7 +1066,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
{
|
||||
let fns = self.device.fns();
|
||||
|
||||
debug_assert!(stages != ShaderStages::none());
|
||||
debug_assert!(!stages.is_empty());
|
||||
debug_assert!(size > 0);
|
||||
debug_assert_eq!(size % 4, 0);
|
||||
debug_assert_eq!(offset % 4, 0);
|
||||
@ -1310,3 +1317,13 @@ impl From<DescriptorSetUpdateError> for BindPushError {
|
||||
Self::DescriptorSetUpdateError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for BindPushError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use crate::{
|
||||
AutoCommandBufferBuilder,
|
||||
},
|
||||
device::DeviceOwned,
|
||||
macros::ExtensionNotEnabled,
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::LogicOp,
|
||||
@ -166,9 +167,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
self
|
||||
}
|
||||
|
||||
fn validate_set_cull_mode(&self, _cull_mode: CullMode) -> Result<(), SetDynamicStateError> {
|
||||
fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::CullMode)?;
|
||||
|
||||
// VUID-vkCmdSetCullMode-cullMode-parameter
|
||||
cull_mode.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetCullMode-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -392,10 +396,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
fn validate_set_depth_compare_op(
|
||||
&self,
|
||||
_compare_op: CompareOp,
|
||||
compare_op: CompareOp,
|
||||
) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?;
|
||||
|
||||
// VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter
|
||||
compare_op.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -586,9 +593,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
self
|
||||
}
|
||||
|
||||
fn validate_set_front_face(&self, _face: FrontFace) -> Result<(), SetDynamicStateError> {
|
||||
fn validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::FrontFace)?;
|
||||
|
||||
// VUID-vkCmdSetFrontFace-frontFace-parameter
|
||||
face.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetFrontFace-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -711,9 +721,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
self
|
||||
}
|
||||
|
||||
fn validate_set_logic_op(&self, _logic_op: LogicOp) -> Result<(), SetDynamicStateError> {
|
||||
fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::LogicOp)?;
|
||||
|
||||
// VUID-vkCmdSetLogicOpEXT-logicOp-parameter
|
||||
logic_op.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -876,6 +889,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?;
|
||||
|
||||
// VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter
|
||||
topology.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -1122,11 +1138,14 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
fn validate_set_stencil_compare_mask(
|
||||
&self,
|
||||
_faces: StencilFaces,
|
||||
faces: StencilFaces,
|
||||
_compare_mask: u32,
|
||||
) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?;
|
||||
|
||||
// VUID-vkCmdSetStencilCompareMask-faceMask-parameter
|
||||
faces.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -1166,14 +1185,29 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
fn validate_set_stencil_op(
|
||||
&self,
|
||||
_faces: StencilFaces,
|
||||
_fail_op: StencilOp,
|
||||
_pass_op: StencilOp,
|
||||
_depth_fail_op: StencilOp,
|
||||
_compare_op: CompareOp,
|
||||
faces: StencilFaces,
|
||||
fail_op: StencilOp,
|
||||
pass_op: StencilOp,
|
||||
depth_fail_op: StencilOp,
|
||||
compare_op: CompareOp,
|
||||
) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::StencilOp)?;
|
||||
|
||||
// VUID-vkCmdSetStencilOp-faceMask-parameter
|
||||
faces.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilOp-failOp-parameter
|
||||
fail_op.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilOp-passOp-parameter
|
||||
pass_op.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilOp-depthFailOp-parameter
|
||||
depth_fail_op.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilOp-compareOp-parameter
|
||||
compare_op.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilOp-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -1211,11 +1245,14 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
fn validate_set_stencil_reference(
|
||||
&self,
|
||||
_faces: StencilFaces,
|
||||
faces: StencilFaces,
|
||||
_reference: u32,
|
||||
) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::StencilReference)?;
|
||||
|
||||
// VUID-vkCmdSetStencilReference-faceMask-parameter
|
||||
faces.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilReference-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -1284,11 +1321,14 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
fn validate_set_stencil_write_mask(
|
||||
&self,
|
||||
_faces: StencilFaces,
|
||||
faces: StencilFaces,
|
||||
_write_mask: u32,
|
||||
) -> Result<(), SetDynamicStateError> {
|
||||
self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?;
|
||||
|
||||
// VUID-vkCmdSetStencilWriteMask-faceMask-parameter
|
||||
faces.validate(self.device())?;
|
||||
|
||||
// VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(SetDynamicStateError::NotSupportedByQueueFamily);
|
||||
@ -2726,3 +2766,13 @@ impl fmt::Display for SetDynamicStateError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for SetDynamicStateError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,15 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
_ne: _,
|
||||
} = blit_image_info;
|
||||
|
||||
// VUID-VkBlitImageInfo2-srcImageLayout-parameter
|
||||
src_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkBlitImageInfo2-dstImageLayout-parameter
|
||||
dst_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkBlitImageInfo2-filter-parameter
|
||||
filter.validate(device)?;
|
||||
|
||||
let src_image_inner = src_image.inner();
|
||||
let dst_image_inner = dst_image.inner();
|
||||
|
||||
@ -209,12 +218,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
sample_count: dst_image.samples(),
|
||||
allowed_sample_counts: SampleCounts {
|
||||
sample1: true,
|
||||
sample2: false,
|
||||
sample4: false,
|
||||
sample8: false,
|
||||
sample16: false,
|
||||
sample32: false,
|
||||
sample64: false,
|
||||
..SampleCounts::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -226,12 +230,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
sample_count: dst_image.samples(),
|
||||
allowed_sample_counts: SampleCounts {
|
||||
sample1: true,
|
||||
sample2: false,
|
||||
sample4: false,
|
||||
sample8: false,
|
||||
sample16: false,
|
||||
sample32: false,
|
||||
sample64: false,
|
||||
..SampleCounts::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -272,13 +271,6 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
}
|
||||
Filter::Cubic => {
|
||||
if !device.enabled_extensions().ext_filter_cubic {
|
||||
return Err(CopyError::ExtensionNotEnabled {
|
||||
extension: "ext_filter_cubic",
|
||||
reason: "the specified filter was Cubic",
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkBlitImageInfo2-filter-02002
|
||||
if !src_image.format_features().sampled_image_filter_cubic {
|
||||
return Err(CopyError::FilterNotSupportedByFormat);
|
||||
@ -335,8 +327,11 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-parameter
|
||||
subresource.aspects.validate(device)?;
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
|
||||
assert!(subresource.aspects != ImageAspects::none());
|
||||
assert!(!subresource.aspects.is_empty());
|
||||
|
||||
// VUID-VkBlitImageInfo2-aspectMask-00241
|
||||
// VUID-VkBlitImageInfo2-aspectMask-00242
|
||||
@ -604,6 +599,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
_ne: _,
|
||||
} = clear_info;
|
||||
|
||||
// VUID-vkCmdClearColorImage-imageLayout-parameter
|
||||
image_layout.validate(device)?;
|
||||
|
||||
// VUID-vkCmdClearColorImage-commonparent
|
||||
assert_eq!(device, image.device());
|
||||
|
||||
@ -663,8 +661,11 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
for (region_index, subresource_range) in regions.iter().enumerate() {
|
||||
// VUID-VkImageSubresourceRange-aspectMask-parameter
|
||||
subresource_range.aspects.validate(device)?;
|
||||
|
||||
// VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
|
||||
assert!(subresource_range.aspects != ImageAspects::none());
|
||||
assert!(!subresource_range.aspects.is_empty());
|
||||
|
||||
// VUID-vkCmdClearColorImage-aspectMask-02498
|
||||
if !image_aspects.contains(&subresource_range.aspects) {
|
||||
@ -746,6 +747,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
_ne: _,
|
||||
} = clear_info;
|
||||
|
||||
// VUID-vkCmdClearDepthStencilImage-imageLayout-parameter
|
||||
image_layout.validate(device)?;
|
||||
|
||||
// VUID-vkCmdClearDepthStencilImage-commonparent
|
||||
assert_eq!(device, image.device());
|
||||
|
||||
@ -802,8 +806,11 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
for (region_index, subresource_range) in regions.iter().enumerate() {
|
||||
// VUID-VkImageSubresourceRange-aspectMask-parameter
|
||||
subresource_range.aspects.validate(device)?;
|
||||
|
||||
// VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
|
||||
assert!(subresource_range.aspects != ImageAspects::none());
|
||||
assert!(!subresource_range.aspects.is_empty());
|
||||
|
||||
// VUID-vkCmdClearDepthStencilImage-aspectMask-02824
|
||||
// VUID-vkCmdClearDepthStencilImage-image-02825
|
||||
@ -893,6 +900,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
_ne: _,
|
||||
} = resolve_image_info;
|
||||
|
||||
// VUID-VkResolveImageInfo2-srcImageLayout-parameter
|
||||
src_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkResolveImageInfo2-dstImageLayout-parameter
|
||||
dst_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkResolveImageInfo2-commonparent
|
||||
assert_eq!(device, src_image.device());
|
||||
assert_eq!(device, dst_image.device());
|
||||
@ -906,13 +919,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
resource: CopyErrorResource::Source,
|
||||
sample_count: dst_image.samples(),
|
||||
allowed_sample_counts: SampleCounts {
|
||||
sample1: false,
|
||||
sample2: true,
|
||||
sample4: true,
|
||||
sample8: true,
|
||||
sample16: true,
|
||||
sample32: true,
|
||||
sample64: true,
|
||||
..SampleCounts::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -924,12 +937,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
sample_count: dst_image.samples(),
|
||||
allowed_sample_counts: SampleCounts {
|
||||
sample1: true,
|
||||
sample2: false,
|
||||
sample4: false,
|
||||
sample8: false,
|
||||
sample16: false,
|
||||
sample32: false,
|
||||
sample64: false,
|
||||
..SampleCounts::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -1019,12 +1027,15 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-parameter
|
||||
subresource.aspects.validate(device)?;
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
|
||||
// VUID-VkImageResolve2-aspectMask-00266
|
||||
if subresource.aspects
|
||||
!= (ImageAspects {
|
||||
color: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
})
|
||||
{
|
||||
return Err(CopyError::AspectsNotAllowed {
|
||||
@ -1033,7 +1044,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
aspects: subresource.aspects,
|
||||
allowed_aspects: ImageAspects {
|
||||
color: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -1177,11 +1188,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -1197,11 +1208,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -1268,11 +1279,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -1338,11 +1349,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -1419,11 +1430,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -1439,11 +1450,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -1966,13 +1977,13 @@ impl Default for ImageBlit {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
src_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
src_offsets: [[0; 3]; 2],
|
||||
dst_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
@ -2192,13 +2203,13 @@ impl Default for ImageResolve {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
src_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
src_offset: [0; 3],
|
||||
dst_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
|
@ -22,6 +22,7 @@ use super::synced::SyncCommandBufferBuilderError;
|
||||
use crate::{
|
||||
format::Format,
|
||||
image::{ImageAspects, ImageLayout, SampleCount, SampleCounts},
|
||||
macros::ExtensionNotEnabled,
|
||||
DeviceSize,
|
||||
};
|
||||
use std::{error::Error, fmt};
|
||||
@ -584,6 +585,16 @@ impl From<SyncCommandBufferBuilderError> for CopyError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for CopyError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates which resource a `CopyError` applies to.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum CopyErrorResource {
|
||||
|
@ -1900,16 +1900,16 @@ impl SyncCommandBufferBuilder {
|
||||
| DescriptorType::StorageBufferDynamic => AccessFlags {
|
||||
shader_read: true,
|
||||
shader_write: false,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
DescriptorType::InputAttachment => AccessFlags {
|
||||
input_attachment_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
DescriptorType::UniformBuffer | DescriptorType::UniformBufferDynamic => {
|
||||
AccessFlags {
|
||||
uniform_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2045,11 +2045,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
vertex_input: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
vertex_attribute_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -2068,11 +2068,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
vertex_input: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
index_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -2093,11 +2093,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
draw_indirect: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: is draw_indirect correct for dispatch too?
|
||||
access: AccessFlags {
|
||||
indirect_command_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
|
@ -16,6 +16,7 @@ use crate::{
|
||||
AutoCommandBufferBuilder,
|
||||
},
|
||||
device::{physical::QueueFamily, DeviceOwned},
|
||||
macros::ExtensionNotEnabled,
|
||||
query::{
|
||||
QueriesRange, Query, QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags,
|
||||
QueryType,
|
||||
@ -72,6 +73,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
let device = self.device();
|
||||
|
||||
// VUID-vkCmdBeginQuery-flags-parameter
|
||||
flags.validate(device)?;
|
||||
|
||||
// VUID-vkCmdBeginQuery-commonparent
|
||||
assert_eq!(device, query_pool.device());
|
||||
|
||||
@ -576,11 +580,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -719,6 +723,10 @@ impl UnsafeCommandBufferBuilder {
|
||||
pub enum QueryError {
|
||||
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
@ -778,6 +786,11 @@ impl fmt::Display for QueryError {
|
||||
"a SyncCommandBufferBuilderError",
|
||||
),
|
||||
|
||||
Self::ExtensionNotEnabled { extension, reason } => write!(
|
||||
f,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
),
|
||||
Self::FeatureNotEnabled { feature, reason } => write!(
|
||||
f,
|
||||
"the feature {} must be enabled: {}",
|
||||
@ -828,3 +841,13 @@ impl From<SyncCommandBufferBuilderError> for QueryError {
|
||||
Self::SyncCommandBufferBuilderError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for QueryError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use crate::{
|
||||
device::DeviceOwned,
|
||||
format::{ClearColorValue, ClearValue, Format, NumericType},
|
||||
image::{ImageLayout, ImageViewAbstract, SampleCount},
|
||||
macros::ExtensionNotEnabled,
|
||||
render_pass::{
|
||||
AttachmentDescription, Framebuffer, LoadOp, RenderPass, ResolveMode, StoreOp,
|
||||
SubpassDescription,
|
||||
@ -88,10 +89,13 @@ where
|
||||
fn validate_begin_render_pass(
|
||||
&self,
|
||||
render_pass_begin_info: &mut RenderPassBeginInfo,
|
||||
_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
) -> Result<(), RenderPassError> {
|
||||
let device = self.device();
|
||||
|
||||
// VUID-VkSubpassBeginInfo-contents-parameter
|
||||
contents.validate(device)?;
|
||||
|
||||
// VUID-vkCmdBeginRenderPass2-commandBuffer-cmdpool
|
||||
if !self.queue_family().supports_graphics() {
|
||||
return Err(RenderPassError::NotSupportedByQueueFamily);
|
||||
@ -412,7 +416,12 @@ where
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn validate_next_subpass(&self, _contents: SubpassContents) -> Result<(), RenderPassError> {
|
||||
fn validate_next_subpass(&self, contents: SubpassContents) -> Result<(), RenderPassError> {
|
||||
let device = self.device();
|
||||
|
||||
// VUID-VkSubpassBeginInfo-contents-parameter
|
||||
contents.validate(device)?;
|
||||
|
||||
// VUID-vkCmdNextSubpass2-renderpass
|
||||
let render_pass_state = self
|
||||
.render_pass_state
|
||||
@ -680,6 +689,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
_ne: _,
|
||||
} = rendering_info;
|
||||
|
||||
// VUID-VkRenderingInfo-flags-parameter
|
||||
contents.validate(device)?;
|
||||
|
||||
// VUID-vkCmdBeginRendering-commandBuffer-06068
|
||||
if self.inheritance_info.is_some() && contents == SubpassContents::SecondaryCommandBuffers {
|
||||
return Err(RenderPassError::ContentsForbiddenInSecondaryCommandBuffer);
|
||||
@ -733,12 +745,21 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
ref image_view,
|
||||
image_layout,
|
||||
ref resolve_info,
|
||||
load_op: _,
|
||||
store_op: _,
|
||||
load_op,
|
||||
store_op,
|
||||
clear_value: _,
|
||||
_ne: _,
|
||||
} = attachment_info;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-imageLayout-parameter
|
||||
image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-loadOp-parameter
|
||||
load_op.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-storeOp-parameter
|
||||
store_op.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingInfo-colorAttachmentCount-06087
|
||||
if !image_view.usage().color_attachment {
|
||||
return Err(RenderPassError::ColorAttachmentMissingUsage { attachment_index });
|
||||
@ -790,6 +811,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
image_layout: resolve_image_layout,
|
||||
} = resolve_info;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
|
||||
resolve_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-resolveMode-parameter
|
||||
mode.validate(device)?;
|
||||
|
||||
let resolve_image = resolve_image_view.image();
|
||||
|
||||
match image_view.format().unwrap().type_color() {
|
||||
@ -867,12 +894,21 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
ref image_view,
|
||||
image_layout,
|
||||
ref resolve_info,
|
||||
load_op: _,
|
||||
store_op: _,
|
||||
load_op,
|
||||
store_op,
|
||||
clear_value: _,
|
||||
_ne: _,
|
||||
} = attachment_info;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-imageLayout-parameter
|
||||
image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-loadOp-parameter
|
||||
load_op.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-storeOp-parameter
|
||||
store_op.validate(device)?;
|
||||
|
||||
let image_aspects = image_view.format().unwrap().aspects();
|
||||
|
||||
// VUID-VkRenderingInfo-pDepthAttachment-06547
|
||||
@ -928,10 +964,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
image_layout: resolve_image_layout,
|
||||
} = resolve_info;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
|
||||
resolve_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-resolveMode-parameter
|
||||
mode.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingInfo-pDepthAttachment-06102
|
||||
if !properties
|
||||
.supported_depth_resolve_modes
|
||||
.map_or(false, |modes| modes.contains(mode))
|
||||
.map_or(false, |modes| modes.contains_mode(mode))
|
||||
{
|
||||
return Err(RenderPassError::DepthAttachmentResolveModeNotSupported);
|
||||
}
|
||||
@ -977,12 +1019,21 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
ref image_view,
|
||||
image_layout,
|
||||
ref resolve_info,
|
||||
load_op: _,
|
||||
store_op: _,
|
||||
load_op,
|
||||
store_op,
|
||||
clear_value: _,
|
||||
_ne: _,
|
||||
} = attachment_info;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-imageLayout-parameter
|
||||
image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-loadOp-parameter
|
||||
load_op.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-storeOp-parameter
|
||||
store_op.validate(device)?;
|
||||
|
||||
let image_aspects = image_view.format().unwrap().aspects();
|
||||
|
||||
// VUID-VkRenderingInfo-pStencilAttachment-06548
|
||||
@ -1038,10 +1089,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
image_layout: resolve_image_layout,
|
||||
} = resolve_info;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
|
||||
resolve_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingAttachmentInfo-resolveMode-parameter
|
||||
mode.validate(device)?;
|
||||
|
||||
// VUID-VkRenderingInfo-pStencilAttachment-06103
|
||||
if !properties
|
||||
.supported_stencil_resolve_modes
|
||||
.map_or(false, |modes| modes.contains(mode))
|
||||
.map_or(false, |modes| modes.contains_mode(mode))
|
||||
{
|
||||
return Err(RenderPassError::StencilAttachmentResolveModeNotSupported);
|
||||
}
|
||||
@ -1207,7 +1264,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
if render_pass_state.contents != SubpassContents::Inline {
|
||||
return Err(RenderPassError::ForbiddenWithSubpassContents {
|
||||
subpass_contents: render_pass_state.contents,
|
||||
contents: render_pass_state.contents,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1423,11 +1480,11 @@ impl SyncCommandBufferBuilder {
|
||||
pub unsafe fn begin_render_pass(
|
||||
&mut self,
|
||||
render_pass_begin_info: RenderPassBeginInfo,
|
||||
subpass_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
) -> Result<(), SyncCommandBufferBuilderError> {
|
||||
struct Cmd {
|
||||
render_pass_begin_info: RenderPassBeginInfo,
|
||||
subpass_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
}
|
||||
|
||||
impl Command for Cmd {
|
||||
@ -1436,7 +1493,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.begin_render_pass(&self.render_pass_begin_info, self.subpass_contents);
|
||||
out.begin_render_pass(&self.render_pass_begin_info, self.contents);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1464,7 +1521,7 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
input_attachment_read: true,
|
||||
@ -1472,7 +1529,7 @@ impl SyncCommandBufferBuilder {
|
||||
color_attachment_write: true,
|
||||
depth_stencil_attachment_read: true,
|
||||
depth_stencil_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal ; note: remember to always pass true if desc.initial_layout != desc.final_layout
|
||||
},
|
||||
@ -1489,7 +1546,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
self.commands.push(Box::new(Cmd {
|
||||
render_pass_begin_info,
|
||||
subpass_contents,
|
||||
contents,
|
||||
}));
|
||||
|
||||
for resource in resources {
|
||||
@ -1503,9 +1560,9 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
/// Calls `vkCmdNextSubpass` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn next_subpass(&mut self, subpass_contents: SubpassContents) {
|
||||
pub unsafe fn next_subpass(&mut self, contents: SubpassContents) {
|
||||
struct Cmd {
|
||||
subpass_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
}
|
||||
|
||||
impl Command for Cmd {
|
||||
@ -1514,11 +1571,11 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.next_subpass(self.subpass_contents);
|
||||
out.next_subpass(self.contents);
|
||||
}
|
||||
}
|
||||
|
||||
self.commands.push(Box::new(Cmd { subpass_contents }));
|
||||
self.commands.push(Box::new(Cmd { contents }));
|
||||
}
|
||||
|
||||
/// Calls `vkCmdEndRenderPass` on the builder.
|
||||
@ -1601,12 +1658,12 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
color_attachment_read: true,
|
||||
color_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal
|
||||
},
|
||||
@ -1629,12 +1686,12 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
color_attachment_read: true,
|
||||
color_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal
|
||||
},
|
||||
@ -1667,12 +1724,12 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
depth_stencil_attachment_read: true,
|
||||
depth_stencil_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal
|
||||
},
|
||||
@ -1695,12 +1752,12 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
depth_stencil_attachment_read: true,
|
||||
depth_stencil_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal
|
||||
},
|
||||
@ -1733,12 +1790,12 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
depth_stencil_attachment_read: true,
|
||||
depth_stencil_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal
|
||||
},
|
||||
@ -1761,12 +1818,12 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
}, // TODO: wrong!
|
||||
access: AccessFlags {
|
||||
depth_stencil_attachment_read: true,
|
||||
depth_stencil_attachment_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
}, // TODO: suboptimal
|
||||
exclusive: true, // TODO: suboptimal
|
||||
},
|
||||
@ -1852,7 +1909,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
pub unsafe fn begin_render_pass(
|
||||
&mut self,
|
||||
render_pass_begin_info: &RenderPassBeginInfo,
|
||||
subpass_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
) {
|
||||
let &RenderPassBeginInfo {
|
||||
ref render_pass,
|
||||
@ -1888,7 +1945,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
};
|
||||
|
||||
let subpass_begin_info = ash::vk::SubpassBeginInfo {
|
||||
contents: subpass_contents.into(),
|
||||
contents: contents.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -1923,11 +1980,11 @@ impl UnsafeCommandBufferBuilder {
|
||||
|
||||
/// Calls `vkCmdNextSubpass` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn next_subpass(&mut self, subpass_contents: SubpassContents) {
|
||||
pub unsafe fn next_subpass(&mut self, contents: SubpassContents) {
|
||||
let fns = self.device.fns();
|
||||
|
||||
let subpass_begin_info = ash::vk::SubpassBeginInfo {
|
||||
contents: subpass_contents.into(),
|
||||
contents: contents.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -2471,6 +2528,10 @@ pub struct ClearRect {
|
||||
pub enum RenderPassError {
|
||||
SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
@ -2619,7 +2680,7 @@ pub enum RenderPassError {
|
||||
|
||||
/// Operation forbidden inside a render subpass with the specified contents.
|
||||
ForbiddenWithSubpassContents {
|
||||
subpass_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
},
|
||||
|
||||
/// The framebuffer is not compatible with the render pass.
|
||||
@ -2734,6 +2795,11 @@ impl fmt::Display for RenderPassError {
|
||||
match self {
|
||||
Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
|
||||
|
||||
Self::ExtensionNotEnabled { extension, reason } => write!(
|
||||
f,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
),
|
||||
Self::FeatureNotEnabled { feature, reason } => {
|
||||
write!(f, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
@ -2910,7 +2976,7 @@ impl fmt::Display for RenderPassError {
|
||||
f,
|
||||
"operation forbidden inside a render pass instance that is inherited by a secondary command buffer",
|
||||
),
|
||||
Self::ForbiddenWithSubpassContents { subpass_contents } => write!(
|
||||
Self::ForbiddenWithSubpassContents { contents: subpass_contents } => write!(
|
||||
f,
|
||||
"operation forbidden inside a render subpass with contents {:?}",
|
||||
subpass_contents,
|
||||
@ -3026,3 +3092,13 @@ impl From<SyncCommandBufferBuilderError> for RenderPassError {
|
||||
Self::SyncCommandBufferBuilderError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for RenderPassError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ where
|
||||
// VUID-vkCmdExecuteCommands-flags-06024
|
||||
if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers {
|
||||
return Err(ExecuteCommandsError::ForbiddenWithSubpassContents {
|
||||
subpass_contents: render_pass_state.contents,
|
||||
contents: render_pass_state.contents,
|
||||
});
|
||||
}
|
||||
|
||||
@ -564,7 +564,7 @@ pub enum ExecuteCommandsError {
|
||||
|
||||
/// Operation forbidden inside a render subpass with the specified contents.
|
||||
ForbiddenWithSubpassContents {
|
||||
subpass_contents: SubpassContents,
|
||||
contents: SubpassContents,
|
||||
},
|
||||
|
||||
/// The queue family doesn't allow this operation.
|
||||
@ -711,7 +711,7 @@ impl fmt::Display for ExecuteCommandsError {
|
||||
write!(f, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
|
||||
Self::ForbiddenWithSubpassContents { subpass_contents } => write!(
|
||||
Self::ForbiddenWithSubpassContents { contents: subpass_contents } => write!(
|
||||
f,
|
||||
"operation forbidden inside a render subpass with contents {:?}",
|
||||
subpass_contents,
|
||||
|
@ -392,7 +392,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
#[inline]
|
||||
pub unsafe fn set_event(&mut self, event: &Event, stages: PipelineStages) {
|
||||
debug_assert!(!stages.host);
|
||||
debug_assert_ne!(stages, PipelineStages::none());
|
||||
debug_assert_ne!(stages, PipelineStages::empty());
|
||||
let fns = self.device.fns();
|
||||
(fns.v1_0.cmd_set_event)(self.handle, event.internal_object(), stages.into());
|
||||
}
|
||||
@ -403,7 +403,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
let fns = self.device.fns();
|
||||
|
||||
debug_assert!(!stages.host);
|
||||
debug_assert_ne!(stages, PipelineStages::none());
|
||||
debug_assert_ne!(stages, PipelineStages::empty());
|
||||
|
||||
(fns.v1_0.cmd_reset_event)(self.handle, event.internal_object(), stages.into());
|
||||
}
|
||||
|
@ -228,6 +228,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
_ne: _,
|
||||
} = copy_image_info;
|
||||
|
||||
// VUID-VkCopyImageInfo2-srcImageLayout-parameter
|
||||
src_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkCopyImageInfo2-dstImageLayout-parameter
|
||||
dst_image_layout.validate(device)?;
|
||||
|
||||
// VUID-VkCopyImageInfo2-commonparent
|
||||
assert_eq!(device, src_image.device());
|
||||
assert_eq!(device, dst_image.device());
|
||||
@ -397,8 +403,11 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-parameter
|
||||
subresource.aspects.validate(device)?;
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
|
||||
assert!(subresource.aspects != ImageAspects::none());
|
||||
assert!(!subresource.aspects.is_empty());
|
||||
|
||||
// VUID-VkCopyImageInfo2-aspectMask-00142
|
||||
// VUID-VkCopyImageInfo2-aspectMask-00143
|
||||
@ -861,19 +870,22 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
let &mut CopyBufferToImageInfo {
|
||||
src_buffer: ref buffer,
|
||||
dst_image: ref image,
|
||||
dst_image_layout: image_layout,
|
||||
ref src_buffer,
|
||||
ref dst_image,
|
||||
dst_image_layout,
|
||||
ref regions,
|
||||
_ne: _,
|
||||
} = copy_buffer_to_image_info;
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-commonparent
|
||||
assert_eq!(device, buffer.device());
|
||||
assert_eq!(device, image.device());
|
||||
// VUID-VkCopyBufferToImageInfo2-dstImageLayout-parameter
|
||||
dst_image_layout.validate(device)?;
|
||||
|
||||
let buffer_inner = buffer.inner();
|
||||
let mut image_aspects = image.format().aspects();
|
||||
// VUID-VkCopyBufferToImageInfo2-commonparent
|
||||
assert_eq!(device, src_buffer.device());
|
||||
assert_eq!(device, dst_image.device());
|
||||
|
||||
let buffer_inner = src_buffer.inner();
|
||||
let mut image_aspects = dst_image.format().aspects();
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-commandBuffer-04477
|
||||
if !self.queue_family().supports_graphics() && !image_aspects.color {
|
||||
@ -881,7 +893,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-srcBuffer-00174
|
||||
if !buffer.usage().transfer_src {
|
||||
if !src_buffer.usage().transfer_src {
|
||||
return Err(CopyError::MissingUsage {
|
||||
resource: CopyErrorResource::Source,
|
||||
usage: "transfer_src",
|
||||
@ -889,7 +901,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-dstImage-00177
|
||||
if !image.usage().transfer_dst {
|
||||
if !dst_image.usage().transfer_dst {
|
||||
return Err(CopyError::MissingUsage {
|
||||
resource: CopyErrorResource::Destination,
|
||||
usage: "transfer_dst",
|
||||
@ -898,7 +910,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
|
||||
// VUID-VkCopyBufferToImageInfo2-dstImage-01997
|
||||
if !image.format_features().transfer_dst {
|
||||
if !dst_image.format_features().transfer_dst {
|
||||
return Err(CopyError::MissingFormatFeature {
|
||||
resource: CopyErrorResource::Destination,
|
||||
format_feature: "transfer_dst",
|
||||
@ -907,30 +919,25 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-dstImage-00179
|
||||
if image.samples() != SampleCount::Sample1 {
|
||||
if dst_image.samples() != SampleCount::Sample1 {
|
||||
return Err(CopyError::SampleCountInvalid {
|
||||
resource: CopyErrorResource::Destination,
|
||||
sample_count: image.samples(),
|
||||
sample_count: dst_image.samples(),
|
||||
allowed_sample_counts: SampleCounts {
|
||||
sample1: true,
|
||||
sample2: false,
|
||||
sample4: false,
|
||||
sample8: false,
|
||||
sample16: false,
|
||||
sample32: false,
|
||||
sample64: false,
|
||||
..SampleCounts::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-dstImageLayout-01396
|
||||
if !matches!(
|
||||
image_layout,
|
||||
dst_image_layout,
|
||||
ImageLayout::TransferDstOptimal | ImageLayout::General
|
||||
) {
|
||||
return Err(CopyError::ImageLayoutInvalid {
|
||||
resource: CopyErrorResource::Destination,
|
||||
image_layout,
|
||||
image_layout: dst_image_layout,
|
||||
});
|
||||
}
|
||||
|
||||
@ -954,7 +961,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
};
|
||||
|
||||
Some(granularity(
|
||||
image.format().block_extent(),
|
||||
dst_image.format().block_extent(),
|
||||
image_aspects.plane0,
|
||||
))
|
||||
}
|
||||
@ -977,12 +984,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
} = region;
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-imageSubresource-01701
|
||||
if image_subresource.mip_level >= image.mip_levels() {
|
||||
if image_subresource.mip_level >= dst_image.mip_levels() {
|
||||
return Err(CopyError::MipLevelsOutOfRange {
|
||||
resource: CopyErrorResource::Destination,
|
||||
region_index,
|
||||
mip_levels_range_end: image_subresource.mip_level + 1,
|
||||
image_mip_levels: image.mip_levels(),
|
||||
image_mip_levels: dst_image.mip_levels(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -992,17 +999,17 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-imageSubresource-01702
|
||||
// VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
|
||||
if image_subresource.array_layers.end > image.dimensions().array_layers() {
|
||||
if image_subresource.array_layers.end > dst_image.dimensions().array_layers() {
|
||||
return Err(CopyError::ArrayLayersOutOfRange {
|
||||
resource: CopyErrorResource::Destination,
|
||||
region_index,
|
||||
array_layers_range_end: image_subresource.array_layers.end,
|
||||
image_array_layers: image.dimensions().array_layers(),
|
||||
image_array_layers: dst_image.dimensions().array_layers(),
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
|
||||
assert!(image_subresource.aspects != ImageAspects::none());
|
||||
assert!(!image_subresource.aspects.is_empty());
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-aspectMask-00211
|
||||
if !image_aspects.contains(&image_subresource.aspects) {
|
||||
@ -1027,32 +1034,32 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
let (image_subresource_format, image_subresource_extent) = if image_aspects.plane0 {
|
||||
if image_subresource.aspects.plane0 {
|
||||
(
|
||||
image.format().planes()[0],
|
||||
image.dimensions().width_height_depth(),
|
||||
dst_image.format().planes()[0],
|
||||
dst_image.dimensions().width_height_depth(),
|
||||
)
|
||||
} else if image_subresource.aspects.plane1 {
|
||||
(
|
||||
image.format().planes()[1],
|
||||
image
|
||||
dst_image.format().planes()[1],
|
||||
dst_image
|
||||
.format()
|
||||
.ycbcr_chroma_sampling()
|
||||
.unwrap()
|
||||
.subsampled_extent(image.dimensions().width_height_depth()),
|
||||
.subsampled_extent(dst_image.dimensions().width_height_depth()),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
image.format().planes()[2],
|
||||
image
|
||||
dst_image.format().planes()[2],
|
||||
dst_image
|
||||
.format()
|
||||
.ycbcr_chroma_sampling()
|
||||
.unwrap()
|
||||
.subsampled_extent(image.dimensions().width_height_depth()),
|
||||
.subsampled_extent(dst_image.dimensions().width_height_depth()),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(
|
||||
image.format(),
|
||||
image
|
||||
dst_image.format(),
|
||||
dst_image
|
||||
.dimensions()
|
||||
.mip_level_dimensions(image_subresource.mip_level)
|
||||
.unwrap()
|
||||
@ -1242,12 +1249,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
|
||||
|
||||
// VUID-VkCopyBufferToImageInfo2-pRegions-00171
|
||||
if buffer_offset + buffer_copy_size > buffer.size() {
|
||||
if buffer_offset + buffer_copy_size > src_buffer.size() {
|
||||
return Err(CopyError::RegionOutOfBufferBounds {
|
||||
resource: CopyErrorResource::Source,
|
||||
region_index,
|
||||
offset_range_end: buffer_offset + buffer_copy_size,
|
||||
buffer_size: buffer.size(),
|
||||
buffer_size: src_buffer.size(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1292,22 +1299,25 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
let &mut CopyImageToBufferInfo {
|
||||
src_image: ref image,
|
||||
src_image_layout: image_layout,
|
||||
dst_buffer: ref buffer,
|
||||
ref src_image,
|
||||
src_image_layout,
|
||||
ref dst_buffer,
|
||||
ref regions,
|
||||
_ne: _,
|
||||
} = copy_image_to_buffer_info;
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-commonparent
|
||||
assert_eq!(device, buffer.device());
|
||||
assert_eq!(device, image.device());
|
||||
// VUID-VkCopyImageToBufferInfo2-srcImageLayout-parameter
|
||||
src_image_layout.validate(device)?;
|
||||
|
||||
let buffer_inner = buffer.inner();
|
||||
let mut image_aspects = image.format().aspects();
|
||||
// VUID-VkCopyImageToBufferInfo2-commonparent
|
||||
assert_eq!(device, dst_buffer.device());
|
||||
assert_eq!(device, src_image.device());
|
||||
|
||||
let buffer_inner = dst_buffer.inner();
|
||||
let mut image_aspects = src_image.format().aspects();
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-srcImage-00186
|
||||
if !image.usage().transfer_src {
|
||||
if !src_image.usage().transfer_src {
|
||||
return Err(CopyError::MissingUsage {
|
||||
resource: CopyErrorResource::Source,
|
||||
usage: "transfer_src",
|
||||
@ -1315,7 +1325,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-dstBuffer-00191
|
||||
if !buffer.usage().transfer_dst {
|
||||
if !dst_buffer.usage().transfer_dst {
|
||||
return Err(CopyError::MissingUsage {
|
||||
resource: CopyErrorResource::Destination,
|
||||
usage: "transfer_dst",
|
||||
@ -1324,7 +1334,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
|
||||
// VUID-VkCopyImageToBufferInfo2-srcImage-01998
|
||||
if !image.format_features().transfer_src {
|
||||
if !src_image.format_features().transfer_src {
|
||||
return Err(CopyError::MissingFormatFeature {
|
||||
resource: CopyErrorResource::Source,
|
||||
format_feature: "transfer_src",
|
||||
@ -1333,30 +1343,25 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-srcImage-00188
|
||||
if image.samples() != SampleCount::Sample1 {
|
||||
if src_image.samples() != SampleCount::Sample1 {
|
||||
return Err(CopyError::SampleCountInvalid {
|
||||
resource: CopyErrorResource::Source,
|
||||
sample_count: image.samples(),
|
||||
sample_count: src_image.samples(),
|
||||
allowed_sample_counts: SampleCounts {
|
||||
sample1: true,
|
||||
sample2: false,
|
||||
sample4: false,
|
||||
sample8: false,
|
||||
sample16: false,
|
||||
sample32: false,
|
||||
sample64: false,
|
||||
..SampleCounts::empty()
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-srcImageLayout-01397
|
||||
if !matches!(
|
||||
image_layout,
|
||||
src_image_layout,
|
||||
ImageLayout::TransferSrcOptimal | ImageLayout::General
|
||||
) {
|
||||
return Err(CopyError::ImageLayoutInvalid {
|
||||
resource: CopyErrorResource::Source,
|
||||
image_layout,
|
||||
image_layout: src_image_layout,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1380,7 +1385,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
};
|
||||
|
||||
Some(granularity(
|
||||
image.format().block_extent(),
|
||||
src_image.format().block_extent(),
|
||||
image_aspects.plane0,
|
||||
))
|
||||
}
|
||||
@ -1403,12 +1408,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
} = region;
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-imageSubresource-01703
|
||||
if image_subresource.mip_level >= image.mip_levels() {
|
||||
if image_subresource.mip_level >= src_image.mip_levels() {
|
||||
return Err(CopyError::MipLevelsOutOfRange {
|
||||
resource: CopyErrorResource::Source,
|
||||
region_index,
|
||||
mip_levels_range_end: image_subresource.mip_level + 1,
|
||||
image_mip_levels: image.mip_levels(),
|
||||
image_mip_levels: src_image.mip_levels(),
|
||||
});
|
||||
}
|
||||
|
||||
@ -1417,17 +1422,17 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-imageSubresource-01704
|
||||
// VUID-VkCopyImageToBufferInfo2-baseArrayLayer-00213
|
||||
if image_subresource.array_layers.end > image.dimensions().array_layers() {
|
||||
if image_subresource.array_layers.end > src_image.dimensions().array_layers() {
|
||||
return Err(CopyError::ArrayLayersOutOfRange {
|
||||
resource: CopyErrorResource::Source,
|
||||
region_index,
|
||||
array_layers_range_end: image_subresource.array_layers.end,
|
||||
image_array_layers: image.dimensions().array_layers(),
|
||||
image_array_layers: src_image.dimensions().array_layers(),
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
|
||||
assert!(image_subresource.aspects != ImageAspects::none());
|
||||
assert!(!image_subresource.aspects.is_empty());
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-aspectMask-00211
|
||||
if !image_aspects.contains(&image_subresource.aspects) {
|
||||
@ -1451,32 +1456,32 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
let (image_subresource_format, image_subresource_extent) = if image_aspects.plane0 {
|
||||
if image_subresource.aspects.plane0 {
|
||||
(
|
||||
image.format().planes()[0],
|
||||
image.dimensions().width_height_depth(),
|
||||
src_image.format().planes()[0],
|
||||
src_image.dimensions().width_height_depth(),
|
||||
)
|
||||
} else if image_subresource.aspects.plane1 {
|
||||
(
|
||||
image.format().planes()[1],
|
||||
image
|
||||
src_image.format().planes()[1],
|
||||
src_image
|
||||
.format()
|
||||
.ycbcr_chroma_sampling()
|
||||
.unwrap()
|
||||
.subsampled_extent(image.dimensions().width_height_depth()),
|
||||
.subsampled_extent(src_image.dimensions().width_height_depth()),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
image.format().planes()[2],
|
||||
image
|
||||
src_image.format().planes()[2],
|
||||
src_image
|
||||
.format()
|
||||
.ycbcr_chroma_sampling()
|
||||
.unwrap()
|
||||
.subsampled_extent(image.dimensions().width_height_depth()),
|
||||
.subsampled_extent(src_image.dimensions().width_height_depth()),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
(
|
||||
image.format(),
|
||||
image
|
||||
src_image.format(),
|
||||
src_image
|
||||
.dimensions()
|
||||
.mip_level_dimensions(image_subresource.mip_level)
|
||||
.unwrap()
|
||||
@ -1666,12 +1671,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
|
||||
|
||||
// VUID-VkCopyImageToBufferInfo2-pRegions-00183
|
||||
if buffer_offset + buffer_copy_size > buffer.size() {
|
||||
if buffer_offset + buffer_copy_size > dst_buffer.size() {
|
||||
return Err(CopyError::RegionOutOfBufferBounds {
|
||||
resource: CopyErrorResource::Destination,
|
||||
region_index,
|
||||
offset_range_end: buffer_offset + buffer_copy_size,
|
||||
buffer_size: buffer.size(),
|
||||
buffer_size: dst_buffer.size(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1945,11 +1950,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -1963,11 +1968,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -2043,11 +2048,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -2063,11 +2068,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -2146,11 +2151,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -2164,11 +2169,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -2248,11 +2253,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_read: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: false,
|
||||
},
|
||||
@ -2269,11 +2274,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -2334,11 +2339,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -2398,11 +2403,11 @@ impl SyncCommandBufferBuilder {
|
||||
memory: PipelineMemoryAccess {
|
||||
stages: PipelineStages {
|
||||
transfer: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
access: AccessFlags {
|
||||
transfer_write: true,
|
||||
..AccessFlags::none()
|
||||
..AccessFlags::empty()
|
||||
},
|
||||
exclusive: true,
|
||||
},
|
||||
@ -3245,13 +3250,13 @@ impl Default for ImageCopy {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
src_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
src_offset: [0; 3],
|
||||
dst_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
@ -3420,7 +3425,7 @@ impl Default for BufferImageCopy {
|
||||
buffer_row_length: 0,
|
||||
buffer_image_height: 0,
|
||||
image_subresource: ImageSubresourceLayers {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
mip_level: 0,
|
||||
array_layers: 0..0,
|
||||
},
|
||||
|
@ -121,6 +121,7 @@ pub use self::{
|
||||
use crate::{
|
||||
format::Format,
|
||||
image::SampleCount,
|
||||
macros::vulkan_enum,
|
||||
query::{QueryControlFlags, QueryPipelineStatisticFlags},
|
||||
render_pass::{Framebuffer, Subpass},
|
||||
};
|
||||
@ -162,21 +163,16 @@ pub struct DispatchIndirectCommand {
|
||||
pub z: u32,
|
||||
}
|
||||
|
||||
/// Describes what a subpass in a command buffer will contain.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum SubpassContents {
|
||||
/// The subpass will only directly contain commands.
|
||||
Inline = ash::vk::SubpassContents::INLINE.as_raw(),
|
||||
/// The subpass will only contain secondary command buffers invocations.
|
||||
SecondaryCommandBuffers = ash::vk::SubpassContents::SECONDARY_COMMAND_BUFFERS.as_raw(),
|
||||
}
|
||||
vulkan_enum! {
|
||||
/// Describes what a subpass in a command buffer will contain.
|
||||
#[non_exhaustive]
|
||||
SubpassContents = SubpassContents(i32);
|
||||
|
||||
impl From<SubpassContents> for ash::vk::SubpassContents {
|
||||
#[inline]
|
||||
fn from(val: SubpassContents) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
/// The subpass will only directly contain commands.
|
||||
Inline = INLINE,
|
||||
|
||||
/// The subpass will only contain secondary command buffers invocations.
|
||||
SecondaryCommandBuffers = SECONDARY_COMMAND_BUFFERS,
|
||||
}
|
||||
|
||||
impl From<SubpassContents> for ash::vk::RenderingFlags {
|
||||
@ -189,24 +185,17 @@ impl From<SubpassContents> for ash::vk::RenderingFlags {
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines the kind of command buffer to create.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(i32)]
|
||||
pub enum CommandBufferLevel {
|
||||
vulkan_enum! {
|
||||
/// Determines the kind of command buffer to create.
|
||||
CommandBufferLevel = CommandBufferLevel(i32);
|
||||
|
||||
/// Primary command buffers can be executed on a queue, and can call secondary command buffers.
|
||||
/// Render passes must begin and end within the same primary command buffer.
|
||||
Primary = ash::vk::CommandBufferLevel::PRIMARY.as_raw(),
|
||||
Primary = PRIMARY,
|
||||
|
||||
/// Secondary command buffers cannot be executed on a queue, but can be executed by a primary
|
||||
/// command buffer. If created for a render pass, they must fit within a single render subpass.
|
||||
Secondary = ash::vk::CommandBufferLevel::SECONDARY.as_raw(),
|
||||
}
|
||||
|
||||
impl From<CommandBufferLevel> for ash::vk::CommandBufferLevel {
|
||||
#[inline]
|
||||
fn from(val: CommandBufferLevel) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
Secondary = SECONDARY,
|
||||
}
|
||||
|
||||
/// The context that a secondary command buffer can inherit from the primary command
|
||||
@ -238,7 +227,7 @@ pub struct CommandBufferInheritanceInfo {
|
||||
/// The `pipeline_statistics_query` feature must be enabled if any of the flags of this value
|
||||
/// are set.
|
||||
///
|
||||
/// The default value is [`QueryPipelineStatisticFlags::none()`].
|
||||
/// The default value is [`QueryPipelineStatisticFlags::empty()`].
|
||||
pub query_statistics_flags: QueryPipelineStatisticFlags,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
@ -250,7 +239,7 @@ impl Default for CommandBufferInheritanceInfo {
|
||||
Self {
|
||||
render_pass: None,
|
||||
occlusion_query: None,
|
||||
query_statistics_flags: QueryPipelineStatisticFlags::none(),
|
||||
query_statistics_flags: QueryPipelineStatisticFlags::empty(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ impl<'a> From<SubmitSemaphoresWaitBuilder<'a>> for SubmitCommandBufferBuilder<'a
|
||||
PipelineStages {
|
||||
// TODO: correct stages ; hard
|
||||
all_commands: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -636,9 +636,9 @@ impl SyncCommandBufferBuilder {
|
||||
ImageMemoryBarrier {
|
||||
source_stages: PipelineStages {
|
||||
bottom_of_pipe: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
source_access: AccessFlags::none(),
|
||||
source_access: AccessFlags::empty(),
|
||||
destination_stages: memory.stages,
|
||||
destination_access: memory.access,
|
||||
old_layout: state.initial_layout,
|
||||
@ -770,9 +770,9 @@ impl SyncCommandBufferBuilder {
|
||||
source_access: state.memory.access,
|
||||
destination_stages: PipelineStages {
|
||||
top_of_pipe: true,
|
||||
..PipelineStages::none()
|
||||
..PipelineStages::empty()
|
||||
},
|
||||
destination_access: AccessFlags::none(),
|
||||
destination_access: AccessFlags::empty(),
|
||||
old_layout: state.current_layout,
|
||||
new_layout: state.final_layout,
|
||||
subresource_range: image.range_to_subresources(range.clone()),
|
||||
|
@ -323,7 +323,7 @@ impl SyncCommandBuffer {
|
||||
range_map
|
||||
.range(&range)
|
||||
.try_fold(
|
||||
(PipelineStages::none(), AccessFlags::none()),
|
||||
(PipelineStages::empty(), AccessFlags::empty()),
|
||||
|(stages, access), (_range, state)| {
|
||||
if !state.exclusive && exclusive {
|
||||
Err(AccessCheckError::Unknown)
|
||||
@ -357,7 +357,7 @@ impl SyncCommandBuffer {
|
||||
range_map
|
||||
.range(&range)
|
||||
.try_fold(
|
||||
(PipelineStages::none(), AccessFlags::none()),
|
||||
(PipelineStages::empty(), AccessFlags::empty()),
|
||||
|(stages, access), (_range, state)| {
|
||||
if expected_layout != ImageLayout::Undefined
|
||||
&& state.final_layout != expected_layout
|
||||
@ -572,9 +572,15 @@ mod tests {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
// Create a tiny test buffer
|
||||
let (buf, future) =
|
||||
DeviceLocalBuffer::from_data(0u32, BufferUsage::transfer_dst(), queue.clone())
|
||||
.unwrap();
|
||||
let (buf, future) = DeviceLocalBuffer::from_data(
|
||||
0u32,
|
||||
BufferUsage {
|
||||
transfer_dst: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
future
|
||||
.then_signal_fence_and_flush()
|
||||
.unwrap()
|
||||
@ -679,8 +685,16 @@ mod tests {
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let buf =
|
||||
CpuAccessibleBuffer::from_data(device, BufferUsage::all(), false, 0u32).unwrap();
|
||||
let buf = CpuAccessibleBuffer::from_data(
|
||||
device,
|
||||
BufferUsage {
|
||||
vertex_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
0u32,
|
||||
)
|
||||
.unwrap();
|
||||
let mut buf_builder = sync.bind_vertex_buffers();
|
||||
buf_builder.add(buf);
|
||||
buf_builder.submit(1);
|
||||
@ -718,7 +732,7 @@ mod tests {
|
||||
bindings: [(
|
||||
0,
|
||||
DescriptorSetLayoutBinding {
|
||||
stages: ShaderStages::all(),
|
||||
stages: ShaderStages::all_graphics(),
|
||||
..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler)
|
||||
},
|
||||
)]
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
macros::{vulkan_enum, ExtensionNotEnabled},
|
||||
sampler::Sampler,
|
||||
shader::{DescriptorRequirements, ShaderStages},
|
||||
OomError, Version, VulkanError, VulkanObject,
|
||||
@ -124,16 +125,29 @@ impl DescriptorSetLayout {
|
||||
let highest_binding_num = bindings.keys().copied().next_back();
|
||||
|
||||
for (&binding_num, binding) in bindings.iter() {
|
||||
if binding.descriptor_count != 0 {
|
||||
*descriptor_counts
|
||||
.entry(binding.descriptor_type)
|
||||
.or_default() += binding.descriptor_count;
|
||||
let &DescriptorSetLayoutBinding {
|
||||
descriptor_type,
|
||||
descriptor_count,
|
||||
variable_descriptor_count,
|
||||
stages,
|
||||
ref immutable_samplers,
|
||||
_ne: _,
|
||||
} = binding;
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorType-parameter
|
||||
descriptor_type.validate(device)?;
|
||||
|
||||
if descriptor_count != 0 {
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorCount-00283
|
||||
stages.validate(device)?;
|
||||
|
||||
*descriptor_counts.entry(descriptor_type).or_default() += descriptor_count;
|
||||
}
|
||||
|
||||
if push_descriptor {
|
||||
// VUID-VkDescriptorSetLayoutCreateInfo-flags-00280
|
||||
if matches!(
|
||||
binding.descriptor_type,
|
||||
descriptor_type,
|
||||
DescriptorType::StorageBufferDynamic | DescriptorType::UniformBufferDynamic
|
||||
) {
|
||||
return Err(
|
||||
@ -144,7 +158,7 @@ impl DescriptorSetLayout {
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003
|
||||
if binding.variable_descriptor_count {
|
||||
if variable_descriptor_count {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::PushDescriptorVariableDescriptorCount {
|
||||
binding_num,
|
||||
@ -153,16 +167,12 @@ impl DescriptorSetLayout {
|
||||
}
|
||||
}
|
||||
|
||||
if !binding.immutable_samplers.is_empty() {
|
||||
if binding
|
||||
.immutable_samplers
|
||||
if !immutable_samplers.is_empty() {
|
||||
if immutable_samplers
|
||||
.iter()
|
||||
.any(|sampler| sampler.sampler_ycbcr_conversion().is_some())
|
||||
{
|
||||
if !matches!(
|
||||
binding.descriptor_type,
|
||||
DescriptorType::CombinedImageSampler
|
||||
) {
|
||||
if !matches!(descriptor_type, DescriptorType::CombinedImageSampler) {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
|
||||
binding_num,
|
||||
@ -171,7 +181,7 @@ impl DescriptorSetLayout {
|
||||
}
|
||||
} else {
|
||||
if !matches!(
|
||||
binding.descriptor_type,
|
||||
descriptor_type,
|
||||
DescriptorType::Sampler | DescriptorType::CombinedImageSampler
|
||||
) {
|
||||
return Err(
|
||||
@ -183,12 +193,12 @@ impl DescriptorSetLayout {
|
||||
}
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
|
||||
if binding.descriptor_count != binding.immutable_samplers.len() as u32 {
|
||||
if descriptor_count != immutable_samplers.len() as u32 {
|
||||
return Err(
|
||||
DescriptorSetLayoutCreationError::ImmutableSamplersCountMismatch {
|
||||
binding_num,
|
||||
sampler_count: binding.immutable_samplers.len() as u32,
|
||||
descriptor_count: binding.descriptor_count,
|
||||
sampler_count: immutable_samplers.len() as u32,
|
||||
descriptor_count,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -197,7 +207,7 @@ impl DescriptorSetLayout {
|
||||
// VUID-VkDescriptorSetLayoutBinding-descriptorType-01510
|
||||
// If descriptorType is VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT and descriptorCount is not 0, then stageFlags must be 0 or VK_SHADER_STAGE_FRAGMENT_BIT
|
||||
|
||||
if binding.variable_descriptor_count {
|
||||
if variable_descriptor_count {
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014
|
||||
if !device
|
||||
.enabled_features()
|
||||
@ -221,7 +231,7 @@ impl DescriptorSetLayout {
|
||||
|
||||
// VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03015
|
||||
if matches!(
|
||||
binding.descriptor_type,
|
||||
descriptor_type,
|
||||
DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
|
||||
) {
|
||||
return Err(
|
||||
@ -561,6 +571,16 @@ impl std::fmt::Display for DescriptorSetLayoutCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for DescriptorSetLayoutCreationError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters to create a new `DescriptorSetLayout`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DescriptorSetLayoutCreateInfo {
|
||||
@ -658,7 +678,7 @@ pub struct DescriptorSetLayoutBinding {
|
||||
|
||||
/// Which shader stages are going to access the descriptors in this binding.
|
||||
///
|
||||
/// The default value is [`ShaderStages::none()`], which must be overridden.
|
||||
/// The default value is [`ShaderStages::empty()`], which must be overridden.
|
||||
pub stages: ShaderStages,
|
||||
|
||||
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
|
||||
@ -683,7 +703,7 @@ impl DescriptorSetLayoutBinding {
|
||||
descriptor_type,
|
||||
descriptor_count: 1,
|
||||
variable_descriptor_count: false,
|
||||
stages: ShaderStages::none(),
|
||||
stages: ShaderStages::empty(),
|
||||
immutable_samplers: Vec::new(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
@ -727,7 +747,7 @@ impl DescriptorSetLayoutBinding {
|
||||
});
|
||||
}
|
||||
|
||||
if !self.stages.is_superset_of(stages) {
|
||||
if !self.stages.contains(stages) {
|
||||
return Err(DescriptorRequirementsNotMet::ShaderStages {
|
||||
required: *stages,
|
||||
obtained: self.stages,
|
||||
@ -794,57 +814,73 @@ impl fmt::Display for DescriptorRequirementsNotMet {
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes what kind of resource may later be bound to a descriptor.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[repr(i32)]
|
||||
#[non_exhaustive]
|
||||
pub enum DescriptorType {
|
||||
vulkan_enum! {
|
||||
/// Describes what kind of resource may later be bound to a descriptor.
|
||||
#[non_exhaustive]
|
||||
DescriptorType = DescriptorType(i32);
|
||||
|
||||
/// Describes how a `SampledImage` descriptor should be read.
|
||||
Sampler = ash::vk::DescriptorType::SAMPLER.as_raw(),
|
||||
Sampler = SAMPLER,
|
||||
|
||||
/// Combines `SampledImage` and `Sampler` in one descriptor.
|
||||
CombinedImageSampler = ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER.as_raw(),
|
||||
CombinedImageSampler = COMBINED_IMAGE_SAMPLER,
|
||||
|
||||
/// Gives read-only access to an image via a sampler. The image must be combined with a sampler
|
||||
/// inside the shader.
|
||||
SampledImage = ash::vk::DescriptorType::SAMPLED_IMAGE.as_raw(),
|
||||
SampledImage = SAMPLED_IMAGE,
|
||||
|
||||
/// Gives read and/or write access to individual pixels in an image. The image cannot be
|
||||
/// sampled, so you have exactly specify which pixel to read or write.
|
||||
StorageImage = ash::vk::DescriptorType::STORAGE_IMAGE.as_raw(),
|
||||
StorageImage = STORAGE_IMAGE,
|
||||
|
||||
/// Gives read-only access to the content of a buffer, interpreted as an array of texel data.
|
||||
UniformTexelBuffer = ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER.as_raw(),
|
||||
UniformTexelBuffer = UNIFORM_TEXEL_BUFFER,
|
||||
|
||||
/// Gives read and/or write access to the content of a buffer, interpreted as an array of texel
|
||||
/// data. Less restrictive but sometimes slower than a uniform texel buffer.
|
||||
StorageTexelBuffer = ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER.as_raw(),
|
||||
StorageTexelBuffer = STORAGE_TEXEL_BUFFER,
|
||||
|
||||
/// Gives read-only access to the content of a buffer, interpreted as a structure.
|
||||
UniformBuffer = ash::vk::DescriptorType::UNIFORM_BUFFER.as_raw(),
|
||||
UniformBuffer = UNIFORM_BUFFER,
|
||||
|
||||
/// Gives read and/or write access to the content of a buffer, interpreted as a structure. Less
|
||||
/// restrictive but sometimes slower than a uniform buffer.
|
||||
StorageBuffer = ash::vk::DescriptorType::STORAGE_BUFFER.as_raw(),
|
||||
StorageBuffer = STORAGE_BUFFER,
|
||||
|
||||
/// As `UniformBuffer`, but the offset within the buffer is specified at the time the descriptor
|
||||
/// set is bound, rather than when the descriptor set is updated.
|
||||
UniformBufferDynamic = ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC.as_raw(),
|
||||
UniformBufferDynamic = UNIFORM_BUFFER_DYNAMIC,
|
||||
|
||||
/// As `StorageBuffer`, but the offset within the buffer is specified at the time the descriptor
|
||||
/// set is bound, rather than when the descriptor set is updated.
|
||||
StorageBufferDynamic = ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC.as_raw(),
|
||||
StorageBufferDynamic = STORAGE_BUFFER_DYNAMIC,
|
||||
|
||||
/// Gives access to an image inside a fragment shader via a render pass. You can only access the
|
||||
/// pixel that is currently being processed by the fragment shader.
|
||||
InputAttachment = ash::vk::DescriptorType::INPUT_ATTACHMENT.as_raw(),
|
||||
}
|
||||
InputAttachment = INPUT_ATTACHMENT,
|
||||
|
||||
impl From<DescriptorType> for ash::vk::DescriptorType {
|
||||
#[inline]
|
||||
fn from(val: DescriptorType) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
/*
|
||||
// TODO: document
|
||||
InlineUniformBlock = INLINE_UNIFORM_BLOCK {
|
||||
api_version: V1_3,
|
||||
extensions: [ext_inline_uniform_block],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
AccelerationStructure = ACCELERATION_STRUCTURE_KHR {
|
||||
extensions: [khr_acceleration_structure],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
AccelerationStructureNV = ACCELERATION_STRUCTURE_NV {
|
||||
extensions: [nv_ray_tracing],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Mutable = MUTABLE_VALVE {
|
||||
extensions: [valve_mutable_descriptor_type],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements};
|
||||
use crate::{instance::InstanceExtensions, Version};
|
||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not, Sub, SubAssign};
|
||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
fmt::Formatter,
|
||||
@ -25,7 +25,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn empty_extensions() {
|
||||
let d: Vec<CString> = (&DeviceExtensions::none()).into();
|
||||
let d: Vec<CString> = (&DeviceExtensions::empty()).into();
|
||||
assert!(d.get(0).is_none());
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::{device::DeviceExtensions, instance::InstanceExtensions, Version};
|
||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not, Sub, SubAssign};
|
||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};
|
||||
use std::fmt::Display;
|
||||
use std::{error::Error, fmt, fmt::Formatter};
|
||||
|
||||
|
@ -34,8 +34,8 @@
|
||||
//! // Here is the device-creating code.
|
||||
//! let device = {
|
||||
//! let queue_family = physical_device.queue_families().next().unwrap();
|
||||
//! let features = Features::none();
|
||||
//! let extensions = DeviceExtensions::none();
|
||||
//! let features = Features::empty();
|
||||
//! let extensions = DeviceExtensions::empty();
|
||||
//!
|
||||
//! match Device::new(
|
||||
//! physical_device,
|
||||
@ -106,6 +106,7 @@ use crate::{
|
||||
command_buffer::pool::StandardCommandPool,
|
||||
descriptor_set::pool::StandardDescriptorPool,
|
||||
instance::{debug::DebugUtilsLabel, Instance},
|
||||
macros::ExtensionNotEnabled,
|
||||
memory::{pool::StandardMemoryPool, ExternalMemoryHandleType},
|
||||
OomError, SynchronizedVulkanObject, Version, VulkanError, VulkanObject,
|
||||
};
|
||||
@ -631,6 +632,9 @@ impl Device {
|
||||
{
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
|
||||
// VUID-vkGetMemoryFdPropertiesKHR-handleType-parameter
|
||||
handle_type.validate(self)?;
|
||||
|
||||
// VUID-vkGetMemoryFdPropertiesKHR-handleType-00674
|
||||
if handle_type == ExternalMemoryHandleType::OpaqueFd {
|
||||
return Err(MemoryFdPropertiesError::InvalidExternalHandleType);
|
||||
@ -839,12 +843,12 @@ impl From<FeatureRestrictionError> for DeviceCreationError {
|
||||
pub struct DeviceCreateInfo<'qf> {
|
||||
/// The extensions to enable on the device.
|
||||
///
|
||||
/// The default value is [`DeviceExtensions::none()`].
|
||||
/// The default value is [`DeviceExtensions::empty()`].
|
||||
pub enabled_extensions: DeviceExtensions,
|
||||
|
||||
/// The features to enable on the device.
|
||||
///
|
||||
/// The default value is [`Features::none()`].
|
||||
/// The default value is [`Features::empty()`].
|
||||
pub enabled_features: Features,
|
||||
|
||||
/// The queues to create for the device.
|
||||
@ -859,8 +863,8 @@ impl Default for DeviceCreateInfo<'static> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled_extensions: DeviceExtensions::none(),
|
||||
enabled_features: Features::none(),
|
||||
enabled_extensions: DeviceExtensions::empty(),
|
||||
enabled_features: Features::empty(),
|
||||
queue_create_infos: Vec::new(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
@ -934,6 +938,11 @@ pub enum MemoryFdPropertiesError {
|
||||
/// No memory available on the host.
|
||||
OutOfHostMemory,
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
|
||||
/// The provided external handle was not valid.
|
||||
InvalidExternalHandle,
|
||||
|
||||
@ -951,6 +960,11 @@ impl fmt::Display for MemoryFdPropertiesError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
Self::OutOfHostMemory => write!(fmt, "no memory available on the host"),
|
||||
Self::ExtensionNotEnabled { extension, reason } => write!(
|
||||
fmt,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
),
|
||||
Self::InvalidExternalHandle => {
|
||||
write!(fmt, "the provided external handle was not valid")
|
||||
}
|
||||
@ -976,6 +990,16 @@ impl From<VulkanError> for MemoryFdPropertiesError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for MemoryFdPropertiesError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a queue where commands can be submitted.
|
||||
// TODO: should use internal synchronization?
|
||||
#[derive(Debug)]
|
||||
@ -1275,7 +1299,7 @@ mod tests {
|
||||
|
||||
let features = Features::all();
|
||||
// In the unlikely situation where the device supports everything, we ignore the test.
|
||||
if physical.supported_features().is_superset_of(&features) {
|
||||
if physical.supported_features().contains(&features) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,12 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::{
|
||||
buffer::{BufferUsage, ExternalBufferInfo, ExternalBufferProperties},
|
||||
buffer::{ExternalBufferInfo, ExternalBufferProperties},
|
||||
device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi},
|
||||
format::{Format, FormatProperties},
|
||||
image::{ImageCreateFlags, ImageFormatInfo, ImageFormatProperties, ImageUsage},
|
||||
instance::{Instance, InstanceCreationError},
|
||||
macros::{vulkan_bitflags, vulkan_enum},
|
||||
swapchain::{
|
||||
ColorSpace, FullScreenExclusive, PresentMode, SupportedSurfaceTransforms, Surface,
|
||||
SurfaceApi, SurfaceCapabilities, SurfaceInfo,
|
||||
@ -458,7 +459,13 @@ impl<'a> PhysicalDevice<'a> {
|
||||
_ne: _,
|
||||
} = info;
|
||||
|
||||
assert!(usage != BufferUsage::none());
|
||||
// VUID-VkPhysicalDeviceExternalBufferInfo-usage-parameter
|
||||
// TODO: usage.validate()?;
|
||||
|
||||
assert!(!usage.is_empty());
|
||||
|
||||
// VUID-VkPhysicalDeviceExternalBufferInfo-handleType-parameter
|
||||
// TODO: handle_type.validate()?;
|
||||
|
||||
let external_buffer_info = ash::vk::PhysicalDeviceExternalBufferInfo {
|
||||
flags: sparse.map(Into::into).unwrap_or_default(),
|
||||
@ -592,6 +599,9 @@ impl<'a> PhysicalDevice<'a> {
|
||||
_ne: _,
|
||||
} = info;
|
||||
|
||||
// VUID-VkPhysicalDeviceExternalSemaphoreInfo-handleType-parameter
|
||||
// TODO: handle_type.validate()?;
|
||||
|
||||
let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
|
||||
handle_type: handle_type.into(),
|
||||
..Default::default()
|
||||
@ -662,12 +672,30 @@ impl<'a> PhysicalDevice<'a> {
|
||||
_ne: _,
|
||||
} = image_format_info;
|
||||
|
||||
// VUID-VkPhysicalDeviceImageFormatInfo2-format-parameter
|
||||
// TODO: format.validate()?;
|
||||
|
||||
// VUID-VkPhysicalDeviceImageFormatInfo2-imageType-parameter
|
||||
// TODO: image_type.validate()?;
|
||||
|
||||
// VUID-VkPhysicalDeviceImageFormatInfo2-tiling-parameter
|
||||
// TODO: tiling.validate()?;
|
||||
|
||||
// VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter
|
||||
// TODO: usage.validate()?;
|
||||
|
||||
// VUID-VkPhysicalDeviceExternalImageFormatInfo-handleType-parameter
|
||||
// TODO: external_memory_handle_type.validate()?;
|
||||
|
||||
// VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter
|
||||
// TODO: image_view_type.validate()?;
|
||||
|
||||
let flags = ImageCreateFlags {
|
||||
mutable_format,
|
||||
cube_compatible,
|
||||
array_2d_compatible,
|
||||
block_texel_view_compatible,
|
||||
..ImageCreateFlags::none()
|
||||
..ImageCreateFlags::empty()
|
||||
};
|
||||
|
||||
let mut format_info2 = ash::vk::PhysicalDeviceImageFormatInfo2::builder()
|
||||
@ -702,7 +730,9 @@ impl<'a> PhysicalDevice<'a> {
|
||||
}
|
||||
|
||||
let mut image_view_image_format_info = if let Some(image_view_type) = image_view_type {
|
||||
if !self.supported_extensions().ext_filter_cubic {
|
||||
if !(self.supported_extensions().ext_filter_cubic
|
||||
|| self.supported_extensions().img_filter_cubic)
|
||||
{
|
||||
// Can't query this, return unsupported
|
||||
return Ok(None);
|
||||
}
|
||||
@ -1342,45 +1372,34 @@ unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of a physical device.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
#[repr(i32)]
|
||||
pub enum PhysicalDeviceType {
|
||||
vulkan_enum! {
|
||||
/// Type of a physical device.
|
||||
#[non_exhaustive]
|
||||
PhysicalDeviceType = PhysicalDeviceType(i32);
|
||||
|
||||
/// The device is an integrated GPU.
|
||||
IntegratedGpu = ash::vk::PhysicalDeviceType::INTEGRATED_GPU.as_raw(),
|
||||
IntegratedGpu = INTEGRATED_GPU,
|
||||
|
||||
/// The device is a discrete GPU.
|
||||
DiscreteGpu = ash::vk::PhysicalDeviceType::DISCRETE_GPU.as_raw(),
|
||||
DiscreteGpu = DISCRETE_GPU,
|
||||
|
||||
/// The device is a virtual GPU.
|
||||
VirtualGpu = ash::vk::PhysicalDeviceType::VIRTUAL_GPU.as_raw(),
|
||||
VirtualGpu = VIRTUAL_GPU,
|
||||
|
||||
/// The device is a CPU.
|
||||
Cpu = ash::vk::PhysicalDeviceType::CPU.as_raw(),
|
||||
Cpu = CPU,
|
||||
|
||||
/// The device is something else.
|
||||
Other = ash::vk::PhysicalDeviceType::OTHER.as_raw(),
|
||||
Other = OTHER,
|
||||
}
|
||||
|
||||
/// VkPhysicalDeviceType::Other is represented as 0
|
||||
impl Default for PhysicalDeviceType {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
PhysicalDeviceType::Other
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
|
||||
type Error = ();
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::PhysicalDeviceType) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
ash::vk::PhysicalDeviceType::INTEGRATED_GPU => Ok(Self::IntegratedGpu),
|
||||
ash::vk::PhysicalDeviceType::DISCRETE_GPU => Ok(Self::DiscreteGpu),
|
||||
ash::vk::PhysicalDeviceType::VIRTUAL_GPU => Ok(Self::VirtualGpu),
|
||||
ash::vk::PhysicalDeviceType::CPU => Ok(Self::Cpu),
|
||||
ash::vk::PhysicalDeviceType::OTHER => Ok(Self::Other),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a memory type in a physical device.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct MemoryType<'a> {
|
||||
@ -1673,131 +1692,115 @@ impl fmt::Display for ConformanceVersion {
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for the driver of a physical device.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum DriverId {
|
||||
AMDProprietary = ash::vk::DriverId::AMD_PROPRIETARY.as_raw(),
|
||||
AMDOpenSource = ash::vk::DriverId::AMD_OPEN_SOURCE.as_raw(),
|
||||
MesaRADV = ash::vk::DriverId::MESA_RADV.as_raw(),
|
||||
NvidiaProprietary = ash::vk::DriverId::NVIDIA_PROPRIETARY.as_raw(),
|
||||
IntelProprietaryWindows = ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS.as_raw(),
|
||||
IntelOpenSourceMesa = ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA.as_raw(),
|
||||
ImaginationProprietary = ash::vk::DriverId::IMAGINATION_PROPRIETARY.as_raw(),
|
||||
QualcommProprietary = ash::vk::DriverId::QUALCOMM_PROPRIETARY.as_raw(),
|
||||
ARMProprietary = ash::vk::DriverId::ARM_PROPRIETARY.as_raw(),
|
||||
GoogleSwiftshader = ash::vk::DriverId::GOOGLE_SWIFTSHADER.as_raw(),
|
||||
GGPProprietary = ash::vk::DriverId::GGP_PROPRIETARY.as_raw(),
|
||||
BroadcomProprietary = ash::vk::DriverId::BROADCOM_PROPRIETARY.as_raw(),
|
||||
MesaLLVMpipe = ash::vk::DriverId::MESA_LLVMPIPE.as_raw(),
|
||||
MoltenVK = ash::vk::DriverId::MOLTENVK.as_raw(),
|
||||
vulkan_enum! {
|
||||
/// An identifier for the driver of a physical device.
|
||||
#[non_exhaustive]
|
||||
DriverId = DriverId(i32);
|
||||
|
||||
// TODO: document
|
||||
AMDProprietary = AMD_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
AMDOpenSource = AMD_OPEN_SOURCE,
|
||||
|
||||
// TODO: document
|
||||
MesaRADV = MESA_RADV,
|
||||
|
||||
// TODO: document
|
||||
NvidiaProprietary = NVIDIA_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
IntelProprietaryWindows = INTEL_PROPRIETARY_WINDOWS,
|
||||
|
||||
// TODO: document
|
||||
IntelOpenSourceMesa = INTEL_OPEN_SOURCE_MESA,
|
||||
|
||||
// TODO: document
|
||||
ImaginationProprietary = IMAGINATION_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
QualcommProprietary = QUALCOMM_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
ARMProprietary = ARM_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
GoogleSwiftshader = GOOGLE_SWIFTSHADER,
|
||||
|
||||
// TODO: document
|
||||
GGPProprietary = GGP_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
BroadcomProprietary = BROADCOM_PROPRIETARY,
|
||||
|
||||
// TODO: document
|
||||
MesaLLVMpipe = MESA_LLVMPIPE,
|
||||
|
||||
// TODO: document
|
||||
MoltenVK = MOLTENVK,
|
||||
}
|
||||
|
||||
impl TryFrom<ash::vk::DriverId> for DriverId {
|
||||
type Error = ();
|
||||
vulkan_bitflags! {
|
||||
/// Specifies which subgroup operations are supported.
|
||||
#[non_exhaustive]
|
||||
SubgroupFeatures = SubgroupFeatureFlags(u32);
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::DriverId) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
ash::vk::DriverId::AMD_PROPRIETARY => Ok(Self::AMDProprietary),
|
||||
ash::vk::DriverId::AMD_OPEN_SOURCE => Ok(Self::AMDOpenSource),
|
||||
ash::vk::DriverId::MESA_RADV => Ok(Self::MesaRADV),
|
||||
ash::vk::DriverId::NVIDIA_PROPRIETARY => Ok(Self::NvidiaProprietary),
|
||||
ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS => Ok(Self::IntelProprietaryWindows),
|
||||
ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA => Ok(Self::IntelOpenSourceMesa),
|
||||
ash::vk::DriverId::IMAGINATION_PROPRIETARY => Ok(Self::ImaginationProprietary),
|
||||
ash::vk::DriverId::QUALCOMM_PROPRIETARY => Ok(Self::QualcommProprietary),
|
||||
ash::vk::DriverId::ARM_PROPRIETARY => Ok(Self::ARMProprietary),
|
||||
ash::vk::DriverId::GOOGLE_SWIFTSHADER => Ok(Self::GoogleSwiftshader),
|
||||
ash::vk::DriverId::GGP_PROPRIETARY => Ok(Self::GGPProprietary),
|
||||
ash::vk::DriverId::BROADCOM_PROPRIETARY => Ok(Self::BroadcomProprietary),
|
||||
ash::vk::DriverId::MESA_LLVMPIPE => Ok(Self::MesaLLVMpipe),
|
||||
ash::vk::DriverId::MOLTENVK => Ok(Self::MoltenVK),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
basic = BASIC,
|
||||
|
||||
// TODO: document
|
||||
vote = VOTE,
|
||||
|
||||
// TODO: document
|
||||
arithmetic = ARITHMETIC,
|
||||
|
||||
// TODO: document
|
||||
ballot = BALLOT,
|
||||
|
||||
// TODO: document
|
||||
shuffle = SHUFFLE,
|
||||
|
||||
// TODO: document
|
||||
shuffle_relative = SHUFFLE_RELATIVE,
|
||||
|
||||
// TODO: document
|
||||
clustered = CLUSTERED,
|
||||
|
||||
// TODO: document
|
||||
quad = QUAD,
|
||||
|
||||
// TODO: document
|
||||
partitioned = PARTITIONED_NV {
|
||||
extensions: [nv_shader_subgroup_partitioned],
|
||||
},
|
||||
}
|
||||
|
||||
/// Specifies which subgroup operations are supported.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SubgroupFeatures {
|
||||
pub basic: bool,
|
||||
pub vote: bool,
|
||||
pub arithmetic: bool,
|
||||
pub ballot: bool,
|
||||
pub shuffle: bool,
|
||||
pub shuffle_relative: bool,
|
||||
pub clustered: bool,
|
||||
pub quad: bool,
|
||||
pub partitioned: bool,
|
||||
vulkan_enum! {
|
||||
/// Specifies how the device clips single point primitives.
|
||||
#[non_exhaustive]
|
||||
PointClippingBehavior = PointClippingBehavior(i32);
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl From<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::SubgroupFeatureFlags) -> Self {
|
||||
Self {
|
||||
basic: val.intersects(ash::vk::SubgroupFeatureFlags::BASIC),
|
||||
vote: val.intersects(ash::vk::SubgroupFeatureFlags::VOTE),
|
||||
arithmetic: val.intersects(ash::vk::SubgroupFeatureFlags::ARITHMETIC),
|
||||
ballot: val.intersects(ash::vk::SubgroupFeatureFlags::BALLOT),
|
||||
shuffle: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE),
|
||||
shuffle_relative: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE),
|
||||
clustered: val.intersects(ash::vk::SubgroupFeatureFlags::CLUSTERED),
|
||||
quad: val.intersects(ash::vk::SubgroupFeatureFlags::QUAD),
|
||||
partitioned: val.intersects(ash::vk::SubgroupFeatureFlags::PARTITIONED_NV),
|
||||
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies how the device clips single point primitives.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum PointClippingBehavior {
|
||||
/// Points are clipped if they lie outside any clip plane, both those bounding the view volume
|
||||
/// and user-defined clip planes.
|
||||
AllClipPlanes = ash::vk::PointClippingBehavior::ALL_CLIP_PLANES.as_raw(),
|
||||
AllClipPlanes = ALL_CLIP_PLANES,
|
||||
|
||||
/// Points are clipped only if they lie outside a user-defined clip plane.
|
||||
UserClipPlanesOnly = ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY.as_raw(),
|
||||
UserClipPlanesOnly = USER_CLIP_PLANES_ONLY,
|
||||
}
|
||||
|
||||
impl TryFrom<ash::vk::PointClippingBehavior> for PointClippingBehavior {
|
||||
type Error = ();
|
||||
vulkan_enum! {
|
||||
/// Specifies whether, and how, shader float controls can be set independently.
|
||||
#[non_exhaustive]
|
||||
ShaderFloatControlsIndependence = ShaderFloatControlsIndependence(i32);
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::PointClippingBehavior) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
ash::vk::PointClippingBehavior::ALL_CLIP_PLANES => Ok(Self::AllClipPlanes),
|
||||
ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY => Ok(Self::UserClipPlanesOnly),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
Float32Only = TYPE_32_ONLY,
|
||||
|
||||
/// Specifies whether, and how, shader float controls can be set independently.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum ShaderFloatControlsIndependence {
|
||||
Float32Only = ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY.as_raw(),
|
||||
All = ash::vk::ShaderFloatControlsIndependence::ALL.as_raw(),
|
||||
None = ash::vk::ShaderFloatControlsIndependence::NONE.as_raw(),
|
||||
}
|
||||
// TODO: document
|
||||
All = ALL,
|
||||
|
||||
impl TryFrom<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
|
||||
type Error = ();
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::ShaderFloatControlsIndependence) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY => Ok(Self::Float32Only),
|
||||
ash::vk::ShaderFloatControlsIndependence::ALL => Ok(Self::All),
|
||||
ash::vk::ShaderFloatControlsIndependence::NONE => Ok(Self::None),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
None = NONE,
|
||||
}
|
||||
|
||||
/// Specifies shader core properties.
|
||||
|
@ -93,9 +93,9 @@
|
||||
//! method on a format.
|
||||
|
||||
use crate::{
|
||||
device::physical::PhysicalDevice, image::ImageAspects, shader::spirv::ImageFormat, DeviceSize,
|
||||
device::physical::PhysicalDevice, image::ImageAspects, macros::vulkan_bitflags,
|
||||
shader::spirv::ImageFormat, DeviceSize,
|
||||
};
|
||||
use std::ops::BitOr;
|
||||
|
||||
// Generated by build.rs
|
||||
include!(concat!(env!("OUT_DIR"), "/formats.rs"));
|
||||
@ -736,313 +736,201 @@ impl FormatProperties {
|
||||
/// <https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/chap43.html#potential-format-features>.
|
||||
#[inline]
|
||||
pub fn potential_format_features(&self) -> FormatFeatures {
|
||||
&self.linear_tiling_features | &self.optimal_tiling_features
|
||||
self.linear_tiling_features | self.optimal_tiling_features
|
||||
}
|
||||
}
|
||||
|
||||
/// The features supported by a device for an image or buffer with a particular format.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct FormatFeatures {
|
||||
// Image usage
|
||||
vulkan_bitflags! {
|
||||
/// The features supported by a device for an image or buffer with a particular format.
|
||||
#[non_exhaustive]
|
||||
FormatFeatures = FormatFeatureFlags2(u64);
|
||||
|
||||
/* Image usage */
|
||||
|
||||
/// Can be used with a sampled image descriptor.
|
||||
pub sampled_image: bool,
|
||||
sampled_image = SAMPLED_IMAGE,
|
||||
|
||||
/// Can be used with a storage image descriptor.
|
||||
pub storage_image: bool,
|
||||
storage_image = STORAGE_IMAGE,
|
||||
|
||||
/// Can be used with a storage image descriptor with atomic operations in a shader.
|
||||
pub storage_image_atomic: bool,
|
||||
storage_image_atomic = STORAGE_IMAGE_ATOMIC,
|
||||
|
||||
/// Can be used with a storage image descriptor for reading, without specifying a format on the
|
||||
/// image view.
|
||||
pub storage_read_without_format: bool,
|
||||
storage_read_without_format = STORAGE_READ_WITHOUT_FORMAT {
|
||||
api_version: V1_3,
|
||||
extensions: [khr_format_feature_flags2],
|
||||
},
|
||||
|
||||
/// Can be used with a storage image descriptor for writing, without specifying a format on the
|
||||
/// image view.
|
||||
pub storage_write_without_format: bool,
|
||||
storage_write_without_format = STORAGE_WRITE_WITHOUT_FORMAT {
|
||||
api_version: V1_3,
|
||||
extensions: [khr_format_feature_flags2],
|
||||
},
|
||||
|
||||
/// Can be used with a color attachment in a framebuffer, or with an input attachment
|
||||
/// descriptor.
|
||||
pub color_attachment: bool,
|
||||
color_attachment = COLOR_ATTACHMENT,
|
||||
|
||||
/// Can be used with a color attachment in a framebuffer with blending, or with an input
|
||||
/// attachment descriptor.
|
||||
pub color_attachment_blend: bool,
|
||||
color_attachment_blend = COLOR_ATTACHMENT_BLEND,
|
||||
|
||||
/// Can be used with a depth/stencil attachment in a framebuffer, or with an input attachment
|
||||
/// descriptor.
|
||||
pub depth_stencil_attachment: bool,
|
||||
/// Can be used with a fragment density map attachment in a framebuffer.
|
||||
pub fragment_density_map: bool,
|
||||
/// Can be used with a fragment shading rate attachment in a framebuffer.
|
||||
pub fragment_shading_rate_attachment: bool,
|
||||
/// Can be used with the source image in a transfer (copy) operation.
|
||||
pub transfer_src: bool,
|
||||
/// Can be used with the destination image in a transfer (copy) operation.
|
||||
pub transfer_dst: bool,
|
||||
/// Can be used with the source image in a blit operation.
|
||||
pub blit_src: bool,
|
||||
/// Can be used with the destination image in a blit operation.
|
||||
pub blit_dst: bool,
|
||||
depth_stencil_attachment = DEPTH_STENCIL_ATTACHMENT,
|
||||
|
||||
/// Can be used with a fragment density map attachment in a framebuffer.
|
||||
fragment_density_map = FRAGMENT_DENSITY_MAP_EXT {
|
||||
extensions: [ext_fragment_density_map],
|
||||
},
|
||||
|
||||
/// Can be used with a fragment shading rate attachment in a framebuffer.
|
||||
fragment_shading_rate_attachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
|
||||
extensions: [khr_fragment_shading_rate],
|
||||
},
|
||||
|
||||
/// Can be used with the source image in a transfer (copy) operation.
|
||||
transfer_src = TRANSFER_SRC {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_maintenance1],
|
||||
},
|
||||
|
||||
/// Can be used with the destination image in a transfer (copy) operation.
|
||||
transfer_dst = TRANSFER_DST {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_maintenance1],
|
||||
},
|
||||
|
||||
/// Can be used with the source image in a blit operation.
|
||||
blit_src = BLIT_SRC,
|
||||
|
||||
/// Can be used with the destination image in a blit operation.
|
||||
blit_dst = BLIT_DST,
|
||||
|
||||
/* Sampling */
|
||||
|
||||
// Sampling
|
||||
/// Can be used with samplers or as a blit source, using the
|
||||
/// [`Linear`](crate::sampler::Filter::Linear) filter.
|
||||
pub sampled_image_filter_linear: bool,
|
||||
sampled_image_filter_linear = SAMPLED_IMAGE_FILTER_LINEAR,
|
||||
|
||||
/// Can be used with samplers or as a blit source, using the
|
||||
/// [`Cubic`](crate::sampler::Filter::Cubic) filter.
|
||||
pub sampled_image_filter_cubic: bool,
|
||||
sampled_image_filter_cubic = SAMPLED_IMAGE_FILTER_CUBIC_EXT {
|
||||
extensions: [ext_filter_cubic, img_filter_cubic],
|
||||
},
|
||||
|
||||
/// Can be used with samplers using a reduction mode of
|
||||
/// [`Min`](crate::sampler::SamplerReductionMode::Min) or
|
||||
/// [`Max`](crate::sampler::SamplerReductionMode::Max).
|
||||
pub sampled_image_filter_minmax: bool,
|
||||
sampled_image_filter_minmax = SAMPLED_IMAGE_FILTER_MINMAX {
|
||||
api_version: V1_2,
|
||||
extensions: [ext_sampler_filter_minmax],
|
||||
},
|
||||
|
||||
/// Can be used with sampler YCbCr conversions using a chroma offset of
|
||||
/// [`Midpoint`](crate::sampler::ycbcr::ChromaLocation::Midpoint).
|
||||
pub midpoint_chroma_samples: bool,
|
||||
midpoint_chroma_samples = MIDPOINT_CHROMA_SAMPLES {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/// Can be used with sampler YCbCr conversions using a chroma offset of
|
||||
/// [`CositedEven`](crate::sampler::ycbcr::ChromaLocation::CositedEven).
|
||||
pub cosited_chroma_samples: bool,
|
||||
cosited_chroma_samples = COSITED_CHROMA_SAMPLES {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/// Can be used with sampler YCbCr conversions using the
|
||||
/// [`Linear`](crate::sampler::Filter::Linear) chroma filter.
|
||||
pub sampled_image_ycbcr_conversion_linear_filter: bool,
|
||||
sampled_image_ycbcr_conversion_linear_filter = SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/// Can be used with sampler YCbCr conversions whose chroma filter differs from the filters of
|
||||
/// the base sampler.
|
||||
pub sampled_image_ycbcr_conversion_separate_reconstruction_filter: bool,
|
||||
sampled_image_ycbcr_conversion_separate_reconstruction_filter = SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/// When used with a sampler YCbCr conversion, the implementation will always perform
|
||||
/// explicit chroma reconstruction.
|
||||
pub sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: bool,
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/// Can be used with sampler YCbCr conversions with forced explicit reconstruction.
|
||||
pub sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: bool,
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/// Can be used with samplers using depth comparison.
|
||||
pub sampled_image_depth_comparison: bool,
|
||||
sampled_image_depth_comparison = SAMPLED_IMAGE_DEPTH_COMPARISON {
|
||||
api_version: V1_3,
|
||||
extensions: [khr_format_feature_flags2],
|
||||
},
|
||||
|
||||
/* Video */
|
||||
|
||||
// Video
|
||||
/// Can be used with the output image of a video decode operation.
|
||||
pub video_decode_output: bool,
|
||||
video_decode_output = VIDEO_DECODE_OUTPUT_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
/// Can be used with the DPB image of a video decode operation.
|
||||
pub video_decode_dpb: bool,
|
||||
video_decode_dpb = VIDEO_DECODE_DPB_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
/// Can be used with the input image of a video encode operation.
|
||||
pub video_encode_input: bool,
|
||||
video_encode_input = VIDEO_ENCODE_INPUT_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
/// Can be used with the DPB image of a video encode operation.
|
||||
pub video_encode_dpb: bool,
|
||||
video_encode_dpb = VIDEO_ENCODE_DPB_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
/* Misc image features */
|
||||
|
||||
// Misc image features
|
||||
/// For multi-planar formats, can be used with images created with the `disjoint` flag.
|
||||
pub disjoint: bool,
|
||||
disjoint = DISJOINT {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
/* Buffer usage */
|
||||
|
||||
// Buffer usage
|
||||
/// Can be used with a uniform texel buffer descriptor.
|
||||
pub uniform_texel_buffer: bool,
|
||||
uniform_texel_buffer = UNIFORM_TEXEL_BUFFER,
|
||||
|
||||
/// Can be used with a storage texel buffer descriptor.
|
||||
pub storage_texel_buffer: bool,
|
||||
storage_texel_buffer = STORAGE_TEXEL_BUFFER,
|
||||
|
||||
/// Can be used with a storage texel buffer descriptor with atomic operations in a shader.
|
||||
pub storage_texel_buffer_atomic: bool,
|
||||
storage_texel_buffer_atomic = STORAGE_TEXEL_BUFFER_ATOMIC,
|
||||
|
||||
/// Can be used as the format of a vertex attribute in the vertex input state of a graphics
|
||||
/// pipeline.
|
||||
pub vertex_buffer: bool,
|
||||
vertex_buffer = VERTEX_BUFFER,
|
||||
|
||||
/// Can be used with the vertex buffer of an acceleration structure.
|
||||
pub acceleration_structure_vertex_buffer: bool,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl Default for FormatFeatures {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
sampled_image: false,
|
||||
storage_image: false,
|
||||
storage_image_atomic: false,
|
||||
storage_read_without_format: false,
|
||||
storage_write_without_format: false,
|
||||
color_attachment: false,
|
||||
color_attachment_blend: false,
|
||||
depth_stencil_attachment: false,
|
||||
fragment_density_map: false,
|
||||
fragment_shading_rate_attachment: false,
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
blit_src: false,
|
||||
blit_dst: false,
|
||||
sampled_image_filter_linear: false,
|
||||
sampled_image_filter_cubic: false,
|
||||
sampled_image_filter_minmax: false,
|
||||
midpoint_chroma_samples: false,
|
||||
cosited_chroma_samples: false,
|
||||
sampled_image_ycbcr_conversion_linear_filter: false,
|
||||
sampled_image_ycbcr_conversion_separate_reconstruction_filter: false,
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: false,
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: false,
|
||||
sampled_image_depth_comparison: false,
|
||||
video_decode_output: false,
|
||||
video_decode_dpb: false,
|
||||
video_encode_input: false,
|
||||
video_encode_dpb: false,
|
||||
disjoint: false,
|
||||
uniform_texel_buffer: false,
|
||||
storage_texel_buffer: false,
|
||||
storage_texel_buffer_atomic: false,
|
||||
vertex_buffer: false,
|
||||
acceleration_structure_vertex_buffer: false,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for &FormatFeatures {
|
||||
type Output = FormatFeatures;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
Self::Output {
|
||||
sampled_image: self.sampled_image || rhs.sampled_image,
|
||||
storage_image: self.storage_image || rhs.storage_image,
|
||||
storage_image_atomic: self.storage_image_atomic || rhs.storage_image_atomic,
|
||||
storage_read_without_format: self.storage_read_without_format
|
||||
|| rhs.storage_read_without_format,
|
||||
storage_write_without_format: self.storage_write_without_format
|
||||
|| rhs.storage_write_without_format,
|
||||
color_attachment: self.color_attachment || rhs.color_attachment,
|
||||
color_attachment_blend: self.color_attachment_blend || rhs.color_attachment_blend,
|
||||
depth_stencil_attachment: self.depth_stencil_attachment || rhs.depth_stencil_attachment,
|
||||
fragment_density_map: self.fragment_density_map || rhs.fragment_density_map,
|
||||
fragment_shading_rate_attachment: self.fragment_shading_rate_attachment
|
||||
|| rhs.fragment_shading_rate_attachment,
|
||||
transfer_src: self.transfer_src || rhs.transfer_src,
|
||||
transfer_dst: self.transfer_dst || rhs.transfer_dst,
|
||||
blit_src: self.blit_src || rhs.blit_src,
|
||||
blit_dst: self.blit_dst || rhs.blit_dst,
|
||||
|
||||
sampled_image_filter_linear: self.sampled_image_filter_linear
|
||||
|| rhs.sampled_image_filter_linear,
|
||||
sampled_image_filter_cubic: self.sampled_image_filter_cubic
|
||||
|| rhs.sampled_image_filter_cubic,
|
||||
sampled_image_filter_minmax: self.sampled_image_filter_minmax
|
||||
|| rhs.sampled_image_filter_minmax,
|
||||
midpoint_chroma_samples: self.midpoint_chroma_samples || rhs.midpoint_chroma_samples,
|
||||
cosited_chroma_samples: self.cosited_chroma_samples || rhs.cosited_chroma_samples,
|
||||
sampled_image_ycbcr_conversion_linear_filter: self
|
||||
.sampled_image_ycbcr_conversion_linear_filter
|
||||
|| rhs.sampled_image_ycbcr_conversion_linear_filter,
|
||||
sampled_image_ycbcr_conversion_separate_reconstruction_filter: self
|
||||
.sampled_image_ycbcr_conversion_separate_reconstruction_filter
|
||||
|| rhs.sampled_image_ycbcr_conversion_separate_reconstruction_filter,
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: self
|
||||
.sampled_image_ycbcr_conversion_chroma_reconstruction_explicit
|
||||
|| rhs.sampled_image_ycbcr_conversion_chroma_reconstruction_explicit,
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: self
|
||||
.sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable
|
||||
|| rhs.sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable,
|
||||
sampled_image_depth_comparison: self.sampled_image_depth_comparison
|
||||
|| rhs.sampled_image_depth_comparison,
|
||||
|
||||
video_decode_output: self.video_decode_output || rhs.video_decode_output,
|
||||
video_decode_dpb: self.video_decode_dpb || rhs.video_decode_dpb,
|
||||
video_encode_input: self.video_encode_input || rhs.video_encode_input,
|
||||
video_encode_dpb: self.video_encode_dpb || rhs.video_encode_dpb,
|
||||
|
||||
disjoint: self.disjoint || rhs.disjoint,
|
||||
|
||||
uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
|
||||
storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
|
||||
storage_texel_buffer_atomic: self.storage_texel_buffer_atomic
|
||||
|| rhs.storage_texel_buffer_atomic,
|
||||
vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
|
||||
acceleration_structure_vertex_buffer: self.acceleration_structure_vertex_buffer
|
||||
|| rhs.acceleration_structure_vertex_buffer,
|
||||
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
acceleration_structure_vertex_buffer = ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR {
|
||||
extensions: [khr_acceleration_structure],
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ash::vk::FormatFeatureFlags> for FormatFeatures {
|
||||
#[inline]
|
||||
#[rustfmt::skip]
|
||||
fn from(val: ash::vk::FormatFeatureFlags) -> FormatFeatures {
|
||||
FormatFeatures {
|
||||
sampled_image: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE),
|
||||
storage_image: val.intersects(ash::vk::FormatFeatureFlags::STORAGE_IMAGE),
|
||||
storage_image_atomic: val.intersects(ash::vk::FormatFeatureFlags::STORAGE_IMAGE_ATOMIC),
|
||||
storage_read_without_format: false, // FormatFeatureFlags2 only
|
||||
storage_write_without_format: false, // FormatFeatureFlags2 only
|
||||
color_attachment: val.intersects(ash::vk::FormatFeatureFlags::COLOR_ATTACHMENT),
|
||||
color_attachment_blend: val.intersects(ash::vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND),
|
||||
depth_stencil_attachment: val.intersects(ash::vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT),
|
||||
fragment_density_map: val.intersects(ash::vk::FormatFeatureFlags::FRAGMENT_DENSITY_MAP_EXT),
|
||||
fragment_shading_rate_attachment: val.intersects(ash::vk::FormatFeatureFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_KHR),
|
||||
transfer_src: val.intersects(ash::vk::FormatFeatureFlags::TRANSFER_SRC),
|
||||
transfer_dst: val.intersects(ash::vk::FormatFeatureFlags::TRANSFER_DST),
|
||||
blit_src: val.intersects(ash::vk::FormatFeatureFlags::BLIT_SRC),
|
||||
blit_dst: val.intersects(ash::vk::FormatFeatureFlags::BLIT_DST),
|
||||
|
||||
sampled_image_filter_linear: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR),
|
||||
sampled_image_filter_cubic: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_CUBIC_EXT),
|
||||
sampled_image_filter_minmax: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_MINMAX),
|
||||
midpoint_chroma_samples: val.intersects(ash::vk::FormatFeatureFlags::MIDPOINT_CHROMA_SAMPLES),
|
||||
cosited_chroma_samples: val.intersects(ash::vk::FormatFeatureFlags::COSITED_CHROMA_SAMPLES),
|
||||
sampled_image_ycbcr_conversion_linear_filter: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER),
|
||||
sampled_image_ycbcr_conversion_separate_reconstruction_filter: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER),
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT),
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: val.intersects(ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE),
|
||||
sampled_image_depth_comparison: false, // FormatFeatureFlags2 only
|
||||
|
||||
video_decode_output: val.intersects(ash::vk::FormatFeatureFlags::VIDEO_DECODE_OUTPUT_KHR),
|
||||
video_decode_dpb: val.intersects(ash::vk::FormatFeatureFlags::VIDEO_DECODE_DPB_KHR),
|
||||
video_encode_input: val.intersects(ash::vk::FormatFeatureFlags::VIDEO_ENCODE_INPUT_KHR),
|
||||
video_encode_dpb: val.intersects(ash::vk::FormatFeatureFlags::VIDEO_ENCODE_DPB_KHR),
|
||||
|
||||
disjoint: val.intersects(ash::vk::FormatFeatureFlags::DISJOINT),
|
||||
|
||||
uniform_texel_buffer: val.intersects(ash::vk::FormatFeatureFlags::UNIFORM_TEXEL_BUFFER),
|
||||
storage_texel_buffer: val.intersects(ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER),
|
||||
storage_texel_buffer_atomic: val.intersects(ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC),
|
||||
vertex_buffer: val.intersects(ash::vk::FormatFeatureFlags::VERTEX_BUFFER),
|
||||
acceleration_structure_vertex_buffer: val.intersects(ash::vk::FormatFeatureFlags::ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR),
|
||||
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::FormatFeatureFlags2> for FormatFeatures {
|
||||
#[inline]
|
||||
#[rustfmt::skip]
|
||||
fn from(val: ash::vk::FormatFeatureFlags2) -> FormatFeatures {
|
||||
FormatFeatures {
|
||||
sampled_image: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE),
|
||||
storage_image: val.intersects(ash::vk::FormatFeatureFlags2::STORAGE_IMAGE),
|
||||
storage_image_atomic: val.intersects(ash::vk::FormatFeatureFlags2::STORAGE_IMAGE_ATOMIC),
|
||||
storage_read_without_format: val.intersects(ash::vk::FormatFeatureFlags2::STORAGE_READ_WITHOUT_FORMAT),
|
||||
storage_write_without_format: val.intersects(ash::vk::FormatFeatureFlags2::STORAGE_WRITE_WITHOUT_FORMAT),
|
||||
color_attachment: val.intersects(ash::vk::FormatFeatureFlags2::COLOR_ATTACHMENT),
|
||||
color_attachment_blend: val.intersects(ash::vk::FormatFeatureFlags2::COLOR_ATTACHMENT_BLEND),
|
||||
depth_stencil_attachment: val.intersects(ash::vk::FormatFeatureFlags2::DEPTH_STENCIL_ATTACHMENT),
|
||||
fragment_density_map: val.intersects(ash::vk::FormatFeatureFlags2::FRAGMENT_DENSITY_MAP_EXT),
|
||||
fragment_shading_rate_attachment: val.intersects(ash::vk::FormatFeatureFlags2::FRAGMENT_SHADING_RATE_ATTACHMENT_KHR),
|
||||
transfer_src: val.intersects(ash::vk::FormatFeatureFlags2::TRANSFER_SRC),
|
||||
transfer_dst: val.intersects(ash::vk::FormatFeatureFlags2::TRANSFER_DST),
|
||||
blit_src: val.intersects(ash::vk::FormatFeatureFlags2::BLIT_SRC),
|
||||
blit_dst: val.intersects(ash::vk::FormatFeatureFlags2::BLIT_DST),
|
||||
|
||||
sampled_image_filter_linear: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_FILTER_LINEAR),
|
||||
sampled_image_filter_cubic: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_FILTER_CUBIC_EXT),
|
||||
sampled_image_filter_minmax: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_FILTER_MINMAX),
|
||||
midpoint_chroma_samples: val.intersects(ash::vk::FormatFeatureFlags2::MIDPOINT_CHROMA_SAMPLES),
|
||||
cosited_chroma_samples: val.intersects(ash::vk::FormatFeatureFlags2::COSITED_CHROMA_SAMPLES),
|
||||
sampled_image_ycbcr_conversion_linear_filter: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER),
|
||||
sampled_image_ycbcr_conversion_separate_reconstruction_filter: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER),
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT),
|
||||
sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE),
|
||||
sampled_image_depth_comparison: val.intersects(ash::vk::FormatFeatureFlags2::SAMPLED_IMAGE_DEPTH_COMPARISON),
|
||||
|
||||
video_decode_output: val.intersects(ash::vk::FormatFeatureFlags2::VIDEO_DECODE_OUTPUT_KHR),
|
||||
video_decode_dpb: val.intersects(ash::vk::FormatFeatureFlags2::VIDEO_DECODE_DPB_KHR),
|
||||
video_encode_input: val.intersects(ash::vk::FormatFeatureFlags2::VIDEO_ENCODE_INPUT_KHR),
|
||||
video_encode_dpb: val.intersects(ash::vk::FormatFeatureFlags2::VIDEO_ENCODE_DPB_KHR),
|
||||
|
||||
disjoint: val.intersects(ash::vk::FormatFeatureFlags2::DISJOINT),
|
||||
|
||||
uniform_texel_buffer: val.intersects(ash::vk::FormatFeatureFlags2::UNIFORM_TEXEL_BUFFER),
|
||||
storage_texel_buffer: val.intersects(ash::vk::FormatFeatureFlags2::STORAGE_TEXEL_BUFFER),
|
||||
storage_texel_buffer_atomic: val.intersects(ash::vk::FormatFeatureFlags2::STORAGE_TEXEL_BUFFER_ATOMIC),
|
||||
vertex_buffer: val.intersects(ash::vk::FormatFeatureFlags2::VERTEX_BUFFER),
|
||||
acceleration_structure_vertex_buffer: val.intersects(ash::vk::FormatFeatureFlags2::ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR),
|
||||
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
fn from(val: ash::vk::FormatFeatureFlags) -> Self {
|
||||
Self::from(ash::vk::FormatFeatureFlags2::from_raw(val.as_raw() as u64))
|
||||
}
|
||||
}
|
||||
|
@ -7,92 +7,113 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::ops::BitOr;
|
||||
use crate::macros::{vulkan_bitflags, vulkan_enum};
|
||||
|
||||
/// An individual data type within an image.
|
||||
///
|
||||
/// Most images have only the `Color` aspect, but some may have several.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[repr(u32)]
|
||||
pub enum ImageAspect {
|
||||
Color = ash::vk::ImageAspectFlags::COLOR.as_raw(),
|
||||
Depth = ash::vk::ImageAspectFlags::DEPTH.as_raw(),
|
||||
Stencil = ash::vk::ImageAspectFlags::STENCIL.as_raw(),
|
||||
Metadata = ash::vk::ImageAspectFlags::METADATA.as_raw(),
|
||||
Plane0 = ash::vk::ImageAspectFlags::PLANE_0.as_raw(),
|
||||
Plane1 = ash::vk::ImageAspectFlags::PLANE_1.as_raw(),
|
||||
Plane2 = ash::vk::ImageAspectFlags::PLANE_2.as_raw(),
|
||||
MemoryPlane0 = ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT.as_raw(),
|
||||
MemoryPlane1 = ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT.as_raw(),
|
||||
MemoryPlane2 = ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT.as_raw(),
|
||||
vulkan_enum! {
|
||||
/// An individual data type within an image.
|
||||
///
|
||||
/// Most images have only the `Color` aspect, but some may have several.
|
||||
#[non_exhaustive]
|
||||
ImageAspect = ImageAspectFlags(u32);
|
||||
|
||||
// TODO: document
|
||||
Color = COLOR,
|
||||
|
||||
// TODO: document
|
||||
Depth = DEPTH,
|
||||
|
||||
// TODO: document
|
||||
Stencil = STENCIL,
|
||||
|
||||
// TODO: document
|
||||
Metadata = METADATA,
|
||||
|
||||
// TODO: document
|
||||
Plane0 = PLANE_0 {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Plane1 = PLANE_1 {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Plane2 = PLANE_2 {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
MemoryPlane0 = MEMORY_PLANE_0_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
MemoryPlane1 = MEMORY_PLANE_1_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
MemoryPlane2 = MEMORY_PLANE_2_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ImageAspect> for ash::vk::ImageAspectFlags {
|
||||
#[inline]
|
||||
fn from(val: ImageAspect) -> Self {
|
||||
Self::from_raw(val as u32)
|
||||
}
|
||||
}
|
||||
vulkan_bitflags! {
|
||||
/// A mask specifying one or more `ImageAspect`s.
|
||||
#[non_exhaustive]
|
||||
ImageAspects = ImageAspectFlags(u32);
|
||||
|
||||
/// A mask specifying one or more `ImageAspect`s.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct ImageAspects {
|
||||
pub color: bool,
|
||||
pub depth: bool,
|
||||
pub stencil: bool,
|
||||
pub metadata: bool,
|
||||
pub plane0: bool,
|
||||
pub plane1: bool,
|
||||
pub plane2: bool,
|
||||
pub memory_plane0: bool,
|
||||
pub memory_plane1: bool,
|
||||
pub memory_plane2: bool,
|
||||
// TODO: document
|
||||
color = COLOR,
|
||||
|
||||
// TODO: document
|
||||
depth = DEPTH,
|
||||
|
||||
// TODO: document
|
||||
stencil = STENCIL,
|
||||
|
||||
// TODO: document
|
||||
metadata = METADATA,
|
||||
|
||||
// TODO: document
|
||||
plane0 = PLANE_0 {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
plane1 = PLANE_1 {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
plane2 = PLANE_2 {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_sampler_ycbcr_conversion],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
memory_plane0 = MEMORY_PLANE_0_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
memory_plane1 = MEMORY_PLANE_1_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
memory_plane2 = MEMORY_PLANE_2_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
}
|
||||
|
||||
impl ImageAspects {
|
||||
/// Builds an `ImageAspect` with all values set to false. Useful as a default value.
|
||||
#[inline]
|
||||
pub const fn none() -> ImageAspects {
|
||||
ImageAspects {
|
||||
color: false,
|
||||
depth: false,
|
||||
stencil: false,
|
||||
metadata: false,
|
||||
plane0: false,
|
||||
plane1: false,
|
||||
plane2: false,
|
||||
memory_plane0: false,
|
||||
memory_plane1: false,
|
||||
memory_plane2: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn contains(&self, other: &Self) -> bool {
|
||||
let Self {
|
||||
color,
|
||||
depth,
|
||||
stencil,
|
||||
metadata,
|
||||
plane0,
|
||||
plane1,
|
||||
plane2,
|
||||
memory_plane0,
|
||||
memory_plane1,
|
||||
memory_plane2,
|
||||
} = *self;
|
||||
|
||||
(color || !other.color)
|
||||
&& (depth || !other.depth)
|
||||
&& (stencil || !other.stencil)
|
||||
&& (metadata || !other.metadata)
|
||||
&& (plane0 || !other.plane0)
|
||||
&& (plane1 || !other.plane1)
|
||||
&& (plane2 || !other.plane2)
|
||||
&& (memory_plane0 || !other.memory_plane0)
|
||||
&& (memory_plane1 || !other.memory_plane1)
|
||||
&& (memory_plane2 || !other.memory_plane2)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = ImageAspect> {
|
||||
let Self {
|
||||
color,
|
||||
@ -105,6 +126,7 @@ impl ImageAspects {
|
||||
memory_plane0,
|
||||
memory_plane1,
|
||||
memory_plane2,
|
||||
_ne: _,
|
||||
} = *self;
|
||||
|
||||
[
|
||||
@ -124,85 +146,9 @@ impl ImageAspects {
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for ImageAspects {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
ImageAspects {
|
||||
color: self.color || rhs.color,
|
||||
depth: self.depth || rhs.depth,
|
||||
stencil: self.stencil || rhs.stencil,
|
||||
metadata: self.metadata || rhs.metadata,
|
||||
plane0: self.plane0 || rhs.plane0,
|
||||
plane1: self.plane1 || rhs.plane1,
|
||||
plane2: self.plane2 || rhs.plane2,
|
||||
memory_plane0: self.memory_plane0 || rhs.memory_plane0,
|
||||
memory_plane1: self.memory_plane1 || rhs.memory_plane1,
|
||||
memory_plane2: self.memory_plane2 || rhs.memory_plane2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageAspects> for ash::vk::ImageAspectFlags {
|
||||
#[inline]
|
||||
fn from(value: ImageAspects) -> ash::vk::ImageAspectFlags {
|
||||
let mut result = ash::vk::ImageAspectFlags::empty();
|
||||
if value.color {
|
||||
result |= ash::vk::ImageAspectFlags::COLOR;
|
||||
}
|
||||
if value.depth {
|
||||
result |= ash::vk::ImageAspectFlags::DEPTH;
|
||||
}
|
||||
if value.stencil {
|
||||
result |= ash::vk::ImageAspectFlags::STENCIL;
|
||||
}
|
||||
if value.metadata {
|
||||
result |= ash::vk::ImageAspectFlags::METADATA;
|
||||
}
|
||||
if value.plane0 {
|
||||
result |= ash::vk::ImageAspectFlags::PLANE_0;
|
||||
}
|
||||
if value.plane1 {
|
||||
result |= ash::vk::ImageAspectFlags::PLANE_1;
|
||||
}
|
||||
if value.plane2 {
|
||||
result |= ash::vk::ImageAspectFlags::PLANE_2;
|
||||
}
|
||||
if value.memory_plane0 {
|
||||
result |= ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT;
|
||||
}
|
||||
if value.memory_plane1 {
|
||||
result |= ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT;
|
||||
}
|
||||
if value.memory_plane2 {
|
||||
result |= ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::ImageAspectFlags> for ImageAspects {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::ImageAspectFlags) -> ImageAspects {
|
||||
ImageAspects {
|
||||
color: !(val & ash::vk::ImageAspectFlags::COLOR).is_empty(),
|
||||
depth: !(val & ash::vk::ImageAspectFlags::DEPTH).is_empty(),
|
||||
stencil: !(val & ash::vk::ImageAspectFlags::STENCIL).is_empty(),
|
||||
metadata: !(val & ash::vk::ImageAspectFlags::METADATA).is_empty(),
|
||||
plane0: !(val & ash::vk::ImageAspectFlags::PLANE_0).is_empty(),
|
||||
plane1: !(val & ash::vk::ImageAspectFlags::PLANE_1).is_empty(),
|
||||
plane2: !(val & ash::vk::ImageAspectFlags::PLANE_2).is_empty(),
|
||||
memory_plane0: !(val & ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT).is_empty(),
|
||||
memory_plane1: !(val & ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT).is_empty(),
|
||||
memory_plane2: !(val & ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT).is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageAspect> for ImageAspects {
|
||||
fn from(aspect: ImageAspect) -> Self {
|
||||
let mut result = Self::none();
|
||||
let mut result = Self::empty();
|
||||
|
||||
match aspect {
|
||||
ImageAspect::Color => result.color = true,
|
||||
@ -223,7 +169,7 @@ impl From<ImageAspect> for ImageAspects {
|
||||
|
||||
impl FromIterator<ImageAspect> for ImageAspects {
|
||||
fn from_iter<T: IntoIterator<Item = ImageAspect>>(iter: T) -> Self {
|
||||
let mut result = Self::none();
|
||||
let mut result = Self::empty();
|
||||
|
||||
for aspect in iter {
|
||||
match aspect {
|
||||
|
@ -97,7 +97,7 @@ impl AttachmentImage {
|
||||
dimensions,
|
||||
1,
|
||||
format,
|
||||
ImageUsage::none(),
|
||||
ImageUsage::empty(),
|
||||
SampleCount::Sample1,
|
||||
)
|
||||
}
|
||||
@ -113,7 +113,7 @@ impl AttachmentImage {
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
let base_usage = ImageUsage {
|
||||
input_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(
|
||||
@ -137,7 +137,7 @@ impl AttachmentImage {
|
||||
samples: SampleCount,
|
||||
format: Format,
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::none(), samples)
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::empty(), samples)
|
||||
}
|
||||
|
||||
/// Same as `multisampled`, but creates an image that can be used as an input attachment.
|
||||
@ -152,7 +152,7 @@ impl AttachmentImage {
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
let base_usage = ImageUsage {
|
||||
input_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
||||
@ -215,7 +215,7 @@ impl AttachmentImage {
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
let base_usage = ImageUsage {
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(
|
||||
@ -240,7 +240,7 @@ impl AttachmentImage {
|
||||
let base_usage = ImageUsage {
|
||||
sampled: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(
|
||||
@ -268,7 +268,7 @@ impl AttachmentImage {
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
let base_usage = ImageUsage {
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
||||
@ -288,7 +288,7 @@ impl AttachmentImage {
|
||||
let base_usage = ImageUsage {
|
||||
sampled: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
||||
@ -308,7 +308,7 @@ impl AttachmentImage {
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
let base_usage = ImageUsage {
|
||||
transient_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(
|
||||
@ -333,7 +333,7 @@ impl AttachmentImage {
|
||||
let base_usage = ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(
|
||||
@ -361,7 +361,7 @@ impl AttachmentImage {
|
||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||
let base_usage = ImageUsage {
|
||||
transient_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
||||
@ -381,7 +381,7 @@ impl AttachmentImage {
|
||||
let base_usage = ImageUsage {
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
||||
@ -508,7 +508,7 @@ impl AttachmentImage {
|
||||
},
|
||||
external_memory_handle_types: ExternalMemoryHandleTypes {
|
||||
opaque_fd: true,
|
||||
..ExternalMemoryHandleTypes::none()
|
||||
..ExternalMemoryHandleTypes::empty()
|
||||
},
|
||||
mutable_format: true,
|
||||
..Default::default()
|
||||
|
@ -137,10 +137,10 @@ impl ImmutableImage {
|
||||
transfer_src: true, // for blits
|
||||
transfer_dst: true,
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
|
||||
let flags = ImageCreateFlags::none();
|
||||
let flags = ImageCreateFlags::empty();
|
||||
|
||||
let (image, _) = ImmutableImage::uninitialized(
|
||||
device,
|
||||
@ -257,7 +257,10 @@ impl ImmutableImage {
|
||||
{
|
||||
let source = CpuAccessibleBuffer::from_iter(
|
||||
queue.device().clone(),
|
||||
BufferUsage::transfer_src(),
|
||||
BufferUsage {
|
||||
transfer_src: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
iter,
|
||||
)?;
|
||||
@ -283,9 +286,9 @@ impl ImmutableImage {
|
||||
transfer_dst: true,
|
||||
transfer_src: need_to_generate_mipmaps,
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
let flags = ImageCreateFlags::none();
|
||||
let flags = ImageCreateFlags::empty();
|
||||
let layout = ImageLayout::ShaderReadOnlyOptimal;
|
||||
|
||||
let (image, initializer) = ImmutableImage::uninitialized(
|
||||
|
@ -7,82 +7,175 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::descriptor_set::layout::DescriptorType;
|
||||
use crate::{descriptor_set::layout::DescriptorType, macros::vulkan_enum};
|
||||
|
||||
vulkan_enum! {
|
||||
/// In-memory layout of the pixel data of an image.
|
||||
///
|
||||
/// The pixel data of a Vulkan image is arranged in a particular way, which is called its *layout*.
|
||||
/// Each image subresource (mipmap level and array layer) in an image can have a different layout,
|
||||
/// but usually the whole image has its data in the same layout. Layouts are abstract in the sense
|
||||
/// that the user does not know the specific details of each layout; the device driver is free to
|
||||
/// implement each layout in the way it sees fit.
|
||||
///
|
||||
/// The layout of a newly created image is either `Undefined` or `Preinitialized`. Every operation
|
||||
/// that can be performed on an image is only possible with specific layouts, so before the
|
||||
/// operation is performed, the user must perform a *layout transition* on the image. This
|
||||
/// rearranges the pixel data from one layout into another. Layout transitions are performed as part
|
||||
/// of pipeline barriers in a command buffer.
|
||||
///
|
||||
/// The `General` layout is compatible with any operation, so layout transitions are never needed.
|
||||
/// However, the other layouts, while more restricted, are usually better optimised for a particular
|
||||
/// type of operation than `General`, so they are usually preferred.
|
||||
///
|
||||
/// Vulkan does not keep track of layouts itself, so it is the responsibility of the user to keep
|
||||
/// track of this information. When performing a layout transition, the previous layout must be
|
||||
/// specified as well. Some operations allow for different layouts, but require the user to specify
|
||||
/// which one. Vulkano helps with this by providing sensible defaults, automatically tracking the
|
||||
/// layout of each image when creating a command buffer, and adding layout transitions where needed.
|
||||
#[non_exhaustive]
|
||||
ImageLayout = ImageLayout(i32);
|
||||
|
||||
/// In-memory layout of the pixel data of an image.
|
||||
///
|
||||
/// The pixel data of a Vulkan image is arranged in a particular way, which is called its *layout*.
|
||||
/// Each image subresource (mipmap level and array layer) in an image can have a different layout,
|
||||
/// but usually the whole image has its data in the same layout. Layouts are abstract in the sense
|
||||
/// that the user does not know the specific details of each layout; the device driver is free to
|
||||
/// implement each layout in the way it sees fit.
|
||||
///
|
||||
/// The layout of a newly created image is either `Undefined` or `Preinitialized`. Every operation
|
||||
/// that can be performed on an image is only possible with specific layouts, so before the
|
||||
/// operation is performed, the user must perform a *layout transition* on the image. This
|
||||
/// rearranges the pixel data from one layout into another. Layout transitions are performed as part
|
||||
/// of pipeline barriers in a command buffer.
|
||||
///
|
||||
/// The `General` layout is compatible with any operation, so layout transitions are never needed.
|
||||
/// However, the other layouts, while more restricted, are usually better optimised for a particular
|
||||
/// type of operation than `General`, so they are usually preferred.
|
||||
///
|
||||
/// Vulkan does not keep track of layouts itself, so it is the responsibility of the user to keep
|
||||
/// track of this information. When performing a layout transition, the previous layout must be
|
||||
/// specified as well. Some operations allow for different layouts, but require the user to specify
|
||||
/// which one. Vulkano helps with this by providing sensible defaults, automatically tracking the
|
||||
/// layout of each image when creating a command buffer, and adding layout transitions where needed.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum ImageLayout {
|
||||
/// The layout of the data is unknown, and the image is treated as containing no valid data.
|
||||
/// Transitioning from `Undefined` will discard any existing pixel data.
|
||||
Undefined = ash::vk::ImageLayout::UNDEFINED.as_raw(),
|
||||
Undefined = UNDEFINED,
|
||||
|
||||
/// A general-purpose layout that can be used for any operation. Some operations may only allow
|
||||
/// `General`, such as storage images, but many have a more specific layout that is better
|
||||
/// optimized for that purpose.
|
||||
General = ash::vk::ImageLayout::GENERAL.as_raw(),
|
||||
General = GENERAL,
|
||||
|
||||
/// For a color image used as a color or resolve attachment in a framebuffer. Images that are
|
||||
/// transitioned into this layout must have the `color_attachment` usage enabled.
|
||||
ColorAttachmentOptimal = ash::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL.as_raw(),
|
||||
ColorAttachmentOptimal = COLOR_ATTACHMENT_OPTIMAL,
|
||||
|
||||
/// For a depth/stencil image used as a depth/stencil attachment in a framebuffer.
|
||||
DepthStencilAttachmentOptimal = ash::vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL.as_raw(),
|
||||
DepthStencilAttachmentOptimal = DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
||||
|
||||
/// For a depth/stencil image used as a read-only depth/stencil attachment in a framebuffer, or
|
||||
/// as a (combined) sampled image or input attachment in a shader.
|
||||
DepthStencilReadOnlyOptimal = ash::vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL.as_raw(),
|
||||
DepthStencilReadOnlyOptimal = DEPTH_STENCIL_READ_ONLY_OPTIMAL,
|
||||
|
||||
/// For a color image used as a (combined) sampled image or input attachment in a shader.
|
||||
/// Images that are transitioned into this layout must have the `sampled` or `input_attachment`
|
||||
/// usages enabled.
|
||||
ShaderReadOnlyOptimal = ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL.as_raw(),
|
||||
ShaderReadOnlyOptimal = SHADER_READ_ONLY_OPTIMAL,
|
||||
|
||||
/// For operations that transfer data from an image (copy, blit).
|
||||
TransferSrcOptimal = ash::vk::ImageLayout::TRANSFER_SRC_OPTIMAL.as_raw(),
|
||||
TransferSrcOptimal = TRANSFER_SRC_OPTIMAL,
|
||||
|
||||
/// For operations that transfer data to an image (copy, blit, clear).
|
||||
TransferDstOptimal = ash::vk::ImageLayout::TRANSFER_DST_OPTIMAL.as_raw(),
|
||||
TransferDstOptimal = TRANSFER_DST_OPTIMAL,
|
||||
|
||||
/// When creating an image, this specifies that the initial data is going to be directly
|
||||
/// written to from the CPU. Unlike `Undefined`, the image is assumed to contain valid data when
|
||||
/// transitioning from this layout. However, this only works right when the image has linear
|
||||
/// tiling, optimal tiling gives undefined results.
|
||||
Preinitialized = ash::vk::ImageLayout::PREINITIALIZED.as_raw(),
|
||||
Preinitialized = PREINITIALIZED,
|
||||
|
||||
/*
|
||||
// TODO: document
|
||||
DepthReadOnlyStencilAttachmentOptimal = DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_maintenance2],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DepthAttachmentStencilReadOnlyOptimal = DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_maintenance2],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DepthAttachmentOptimal = DEPTH_ATTACHMENT_OPTIMAL {
|
||||
api_version: V1_2,
|
||||
extensions: [khr_separate_depth_stencil_layouts],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DepthReadOnlyOptimal = DEPTH_READ_ONLY_OPTIMAL {
|
||||
api_version: V1_2,
|
||||
extensions: [khr_separate_depth_stencil_layouts],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
StencilAttachmentOptimal = STENCIL_ATTACHMENT_OPTIMAL {
|
||||
api_version: V1_2,
|
||||
extensions: [khr_separate_depth_stencil_layouts],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
StencilReadOnlyOptimal = STENCIL_READ_ONLY_OPTIMAL {
|
||||
api_version: V1_2,
|
||||
extensions: [khr_separate_depth_stencil_layouts],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
ReadOnlyOptimal = READ_ONLY_OPTIMAL {
|
||||
api_version: V1_3,
|
||||
extensions: [khr_synchronization2],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
AttachmentOptimal = ATTACHMENT_OPTIMAL {
|
||||
api_version: V1_3,
|
||||
extensions: [khr_synchronization2],
|
||||
},
|
||||
*/
|
||||
|
||||
/// The layout of images that are held in a swapchain. Images are in this layout when they are
|
||||
/// acquired from the swapchain, and must be transitioned back into this layout before
|
||||
/// presenting them.
|
||||
PresentSrc = ash::vk::ImageLayout::PRESENT_SRC_KHR.as_raw(),
|
||||
}
|
||||
PresentSrc = PRESENT_SRC_KHR {
|
||||
extensions: [khr_swapchain],
|
||||
},
|
||||
|
||||
impl From<ImageLayout> for ash::vk::ImageLayout {
|
||||
#[inline]
|
||||
fn from(val: ImageLayout) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
/*
|
||||
// TODO: document
|
||||
VideoDecodeDst = VIDEO_DECODE_DST_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
VideoDecodeSrc = VIDEO_DECODE_SRC_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
VideoDecodeDpb = VIDEO_DECODE_DPB_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
SharedPresent = SHARED_PRESENT_KHR {
|
||||
extensions: [khr_shared_presentable_image],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
FragmentDensityMapOptimal = FRAGMENT_DENSITY_MAP_OPTIMAL_EXT {
|
||||
extensions: [ext_fragment_density_map],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
FragmentShadingRateAttachmentOptimal = FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR {
|
||||
extensions: [khr_fragment_shading_rate],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
VideoEncodeDst = VIDEO_ENCODE_DST_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
VideoEncodeSrc = VIDEO_ENCODE_SRC_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
VideoEncodeDpb = VIDEO_ENCODE_DPB_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
/// The set of layouts to use for an image when used in descriptor of various kinds.
|
||||
|
@ -60,13 +60,11 @@ pub use self::{
|
||||
};
|
||||
use crate::{
|
||||
format::Format,
|
||||
macros::{vulkan_bitflags, vulkan_enum},
|
||||
memory::{ExternalMemoryHandleType, ExternalMemoryProperties},
|
||||
DeviceSize,
|
||||
};
|
||||
use std::{
|
||||
cmp,
|
||||
ops::{BitAnd, Range},
|
||||
};
|
||||
use std::{cmp, ops::Range};
|
||||
|
||||
mod aspect;
|
||||
pub mod attachment; // TODO: make private
|
||||
@ -79,41 +77,31 @@ pub mod traits;
|
||||
mod usage;
|
||||
pub mod view;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
pub enum SampleCount {
|
||||
Sample1 = ash::vk::SampleCountFlags::TYPE_1.as_raw(),
|
||||
Sample2 = ash::vk::SampleCountFlags::TYPE_2.as_raw(),
|
||||
Sample4 = ash::vk::SampleCountFlags::TYPE_4.as_raw(),
|
||||
Sample8 = ash::vk::SampleCountFlags::TYPE_8.as_raw(),
|
||||
Sample16 = ash::vk::SampleCountFlags::TYPE_16.as_raw(),
|
||||
Sample32 = ash::vk::SampleCountFlags::TYPE_32.as_raw(),
|
||||
Sample64 = ash::vk::SampleCountFlags::TYPE_64.as_raw(),
|
||||
}
|
||||
vulkan_enum! {
|
||||
// TODO: document
|
||||
#[non_exhaustive]
|
||||
SampleCount = SampleCountFlags(u32);
|
||||
|
||||
impl From<SampleCount> for ash::vk::SampleCountFlags {
|
||||
#[inline]
|
||||
fn from(val: SampleCount) -> Self {
|
||||
Self::from_raw(val as u32)
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
Sample1 = TYPE_1,
|
||||
|
||||
impl TryFrom<ash::vk::SampleCountFlags> for SampleCount {
|
||||
type Error = ();
|
||||
// TODO: document
|
||||
Sample2 = TYPE_2,
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::SampleCountFlags) -> Result<Self, Self::Error> {
|
||||
match val {
|
||||
ash::vk::SampleCountFlags::TYPE_1 => Ok(Self::Sample1),
|
||||
ash::vk::SampleCountFlags::TYPE_2 => Ok(Self::Sample2),
|
||||
ash::vk::SampleCountFlags::TYPE_4 => Ok(Self::Sample4),
|
||||
ash::vk::SampleCountFlags::TYPE_8 => Ok(Self::Sample8),
|
||||
ash::vk::SampleCountFlags::TYPE_16 => Ok(Self::Sample16),
|
||||
ash::vk::SampleCountFlags::TYPE_32 => Ok(Self::Sample32),
|
||||
ash::vk::SampleCountFlags::TYPE_64 => Ok(Self::Sample64),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
Sample4 = TYPE_4,
|
||||
|
||||
// TODO: document
|
||||
Sample8 = TYPE_8,
|
||||
|
||||
// TODO: document
|
||||
Sample16 = TYPE_16,
|
||||
|
||||
// TODO: document
|
||||
Sample32 = TYPE_32,
|
||||
|
||||
// TODO: document
|
||||
Sample64 = TYPE_64,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for SampleCount {
|
||||
@ -134,29 +122,37 @@ impl TryFrom<u32> for SampleCount {
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies how many sample counts supported for an image used for storage operations.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SampleCounts {
|
||||
// specify an image with one sample per pixel
|
||||
pub sample1: bool,
|
||||
// specify an image with 2 samples per pixel
|
||||
pub sample2: bool,
|
||||
// specify an image with 4 samples per pixel
|
||||
pub sample4: bool,
|
||||
// specify an image with 8 samples per pixel
|
||||
pub sample8: bool,
|
||||
// specify an image with 16 samples per pixel
|
||||
pub sample16: bool,
|
||||
// specify an image with 32 samples per pixel
|
||||
pub sample32: bool,
|
||||
// specify an image with 64 samples per pixel
|
||||
pub sample64: bool,
|
||||
vulkan_bitflags! {
|
||||
/// Specifies a set of [`SampleCount`] values.
|
||||
#[non_exhaustive]
|
||||
SampleCounts = SampleCountFlags(u32);
|
||||
|
||||
/// 1 sample per pixel.
|
||||
sample1 = TYPE_1,
|
||||
|
||||
/// 2 samples per pixel.
|
||||
sample2 = TYPE_2,
|
||||
|
||||
/// 4 samples per pixel.
|
||||
sample4 = TYPE_4,
|
||||
|
||||
/// 8 samples per pixel.
|
||||
sample8 = TYPE_8,
|
||||
|
||||
/// 16 samples per pixel.
|
||||
sample16 = TYPE_16,
|
||||
|
||||
/// 32 samples per pixel.
|
||||
sample32 = TYPE_32,
|
||||
|
||||
/// 64 samples per pixel.
|
||||
sample64 = TYPE_64,
|
||||
}
|
||||
|
||||
impl SampleCounts {
|
||||
/// Returns true if `self` has the `sample_count` value set.
|
||||
#[inline]
|
||||
pub const fn contains(&self, sample_count: SampleCount) -> bool {
|
||||
pub const fn contains_count(&self, sample_count: SampleCount) -> bool {
|
||||
match sample_count {
|
||||
SampleCount::Sample1 => self.sample1,
|
||||
SampleCount::Sample2 => self.sample2,
|
||||
@ -168,41 +164,6 @@ impl SampleCounts {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the intersection of these sample counts and another set of sample counts.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// If you're using both a color and depth buffer, and want to use multisampling, then you
|
||||
/// should check the intersection of the supported sample counts because they don't have to
|
||||
/// match. You could similarily apply this to the stencil counts.
|
||||
/// ```no_run
|
||||
/// # use vulkano::{
|
||||
/// # instance::Instance,
|
||||
/// # device::physical::PhysicalDevice,
|
||||
/// # VulkanLibrary,
|
||||
/// # };
|
||||
/// # let library = VulkanLibrary::new().unwrap();
|
||||
/// # let instance = Instance::new(library, Default::default()).unwrap();
|
||||
/// # let physical_device = PhysicalDevice::from_index(&instance, 0).unwrap();
|
||||
/// let properties = physical_device.properties();
|
||||
/// let color_counts = properties.framebuffer_color_sample_counts;
|
||||
/// let depth_counts = properties.framebuffer_depth_sample_counts;
|
||||
///
|
||||
/// let counts = color_counts.intersection(&depth_counts);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn intersection(&self, other: &SampleCounts) -> SampleCounts {
|
||||
SampleCounts {
|
||||
sample1: self.sample1 && other.sample1,
|
||||
sample2: self.sample2 && other.sample2,
|
||||
sample4: self.sample4 && other.sample4,
|
||||
sample8: self.sample8 && other.sample8,
|
||||
sample16: self.sample16 && other.sample16,
|
||||
sample32: self.sample32 && other.sample32,
|
||||
sample64: self.sample64 && other.sample64,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the maximum sample count supported by `self`.
|
||||
#[inline]
|
||||
pub const fn max_count(&self) -> SampleCount {
|
||||
@ -218,66 +179,6 @@ impl SampleCounts {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::SampleCountFlags> for SampleCounts {
|
||||
fn from(sample_counts: ash::vk::SampleCountFlags) -> SampleCounts {
|
||||
SampleCounts {
|
||||
sample1: !(sample_counts & ash::vk::SampleCountFlags::TYPE_1).is_empty(),
|
||||
sample2: !(sample_counts & ash::vk::SampleCountFlags::TYPE_2).is_empty(),
|
||||
sample4: !(sample_counts & ash::vk::SampleCountFlags::TYPE_4).is_empty(),
|
||||
sample8: !(sample_counts & ash::vk::SampleCountFlags::TYPE_8).is_empty(),
|
||||
sample16: !(sample_counts & ash::vk::SampleCountFlags::TYPE_16).is_empty(),
|
||||
sample32: !(sample_counts & ash::vk::SampleCountFlags::TYPE_32).is_empty(),
|
||||
sample64: !(sample_counts & ash::vk::SampleCountFlags::TYPE_64).is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SampleCounts> for ash::vk::SampleCountFlags {
|
||||
fn from(val: SampleCounts) -> ash::vk::SampleCountFlags {
|
||||
let mut sample_counts = ash::vk::SampleCountFlags::default();
|
||||
|
||||
if val.sample1 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_1;
|
||||
}
|
||||
if val.sample2 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_2;
|
||||
}
|
||||
if val.sample4 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_4;
|
||||
}
|
||||
if val.sample8 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_8;
|
||||
}
|
||||
if val.sample16 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_16;
|
||||
}
|
||||
if val.sample32 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_32;
|
||||
}
|
||||
if val.sample64 {
|
||||
sample_counts |= ash::vk::SampleCountFlags::TYPE_64;
|
||||
}
|
||||
|
||||
sample_counts
|
||||
}
|
||||
}
|
||||
|
||||
impl BitAnd for SampleCounts {
|
||||
type Output = SampleCounts;
|
||||
|
||||
fn bitand(self, rhs: Self) -> Self::Output {
|
||||
SampleCounts {
|
||||
sample1: self.sample1 && rhs.sample1,
|
||||
sample2: self.sample2 && rhs.sample2,
|
||||
sample4: self.sample4 && rhs.sample4,
|
||||
sample8: self.sample8 && rhs.sample8,
|
||||
sample16: self.sample16 && rhs.sample16,
|
||||
sample32: self.sample32 && rhs.sample32,
|
||||
sample64: self.sample64 && rhs.sample64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specifies how many mipmaps must be allocated.
|
||||
///
|
||||
/// Note that at least one mipmap must be allocated, to store the main level of the image.
|
||||
@ -305,14 +206,17 @@ impl From<u32> for MipmapsCount {
|
||||
}
|
||||
}
|
||||
|
||||
/// Flags that can be set when creating a new image.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
|
||||
pub struct ImageCreateFlags {
|
||||
vulkan_bitflags! {
|
||||
/// Flags that can be set when creating a new image.
|
||||
#[non_exhaustive]
|
||||
ImageCreateFlags = ImageCreateFlags(u32);
|
||||
|
||||
/// The image will be backed by sparsely bound memory.
|
||||
///
|
||||
/// Requires the [`sparse_binding`](crate::device::Features::sparse_binding) feature to be
|
||||
/// enabled.
|
||||
pub sparse_binding: bool,
|
||||
sparse_binding = SPARSE_BINDING,
|
||||
|
||||
/// The image is allowed to be only partially resident in memory, not all parts of the image
|
||||
/// must be backed by memory.
|
||||
///
|
||||
@ -321,98 +225,73 @@ pub struct ImageCreateFlags {
|
||||
/// [`sparse_residency_image3_d`](crate::device::Features::sparse_residency_image3_d) feature to
|
||||
/// be enabled. For a multisampled image, this also requires the appropriate sparse residency
|
||||
/// feature for the number of samples to be enabled.
|
||||
pub sparse_residency: bool,
|
||||
sparse_residency = SPARSE_RESIDENCY,
|
||||
|
||||
/// The image can be backed by memory that is shared (aliased) with other images.
|
||||
///
|
||||
/// Requires the `sparse_binding` flag and the
|
||||
/// [`sparse_residency_aliased`](crate::device::Features::sparse_residency_aliased) feature to
|
||||
/// be enabled.
|
||||
pub sparse_aliased: bool,
|
||||
sparse_aliased = SPARSE_ALIASED,
|
||||
|
||||
/// For non-multi-planar formats, an image view wrapping this image can have a different format.
|
||||
///
|
||||
/// For multi-planar formats, an image view wrapping this image can be created from a single
|
||||
/// plane of the image.
|
||||
pub mutable_format: bool,
|
||||
mutable_format = MUTABLE_FORMAT,
|
||||
|
||||
/// For 2D images, allows creation of an image view of type `Cube` or `CubeArray`.
|
||||
pub cube_compatible: bool,
|
||||
cube_compatible = CUBE_COMPATIBLE,
|
||||
|
||||
/// For 3D images, allows creation of an image view of type `Dim2d` or `Dim2dArray`.
|
||||
pub array_2d_compatible: bool,
|
||||
array_2d_compatible = TYPE_2D_ARRAY_COMPATIBLE {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_maintenance1],
|
||||
},
|
||||
|
||||
/// For images with a compressed format, allows creation of an image view with an uncompressed
|
||||
/// format, where each texel in the view will correspond to a compressed texel block in the
|
||||
/// image.
|
||||
///
|
||||
/// Requires `mutable_format`.
|
||||
pub block_texel_view_compatible: bool,
|
||||
block_texel_view_compatible = BLOCK_TEXEL_VIEW_COMPATIBLE {
|
||||
api_version: V1_1,
|
||||
extensions: [khr_maintenance1],
|
||||
},
|
||||
}
|
||||
|
||||
impl ImageCreateFlags {
|
||||
pub fn none() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
vulkan_enum! {
|
||||
// TODO: document
|
||||
#[non_exhaustive]
|
||||
ImageType = ImageType(i32);
|
||||
|
||||
// TODO: document
|
||||
Dim1d = TYPE_1D,
|
||||
|
||||
// TODO: document
|
||||
Dim2d = TYPE_2D,
|
||||
|
||||
// TODO: document
|
||||
Dim3d = TYPE_3D,
|
||||
}
|
||||
|
||||
impl From<ImageCreateFlags> for ash::vk::ImageCreateFlags {
|
||||
fn from(flags: ImageCreateFlags) -> Self {
|
||||
let ImageCreateFlags {
|
||||
sparse_binding,
|
||||
sparse_residency,
|
||||
sparse_aliased,
|
||||
mutable_format,
|
||||
cube_compatible,
|
||||
array_2d_compatible,
|
||||
block_texel_view_compatible,
|
||||
} = flags;
|
||||
vulkan_enum! {
|
||||
// TODO: document
|
||||
#[non_exhaustive]
|
||||
ImageTiling = ImageTiling(i32);
|
||||
|
||||
let mut vk_flags = Self::default();
|
||||
if sparse_binding {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::SPARSE_BINDING
|
||||
};
|
||||
if sparse_residency {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::SPARSE_RESIDENCY
|
||||
};
|
||||
if sparse_aliased {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::SPARSE_ALIASED
|
||||
};
|
||||
if mutable_format {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::MUTABLE_FORMAT
|
||||
};
|
||||
if cube_compatible {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::CUBE_COMPATIBLE
|
||||
};
|
||||
if array_2d_compatible {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::TYPE_2D_ARRAY_COMPATIBLE
|
||||
};
|
||||
if block_texel_view_compatible {
|
||||
vk_flags |= ash::vk::ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE
|
||||
};
|
||||
vk_flags
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
Optimal = OPTIMAL,
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum ImageType {
|
||||
Dim1d = ash::vk::ImageType::TYPE_1D.as_raw(),
|
||||
Dim2d = ash::vk::ImageType::TYPE_2D.as_raw(),
|
||||
Dim3d = ash::vk::ImageType::TYPE_3D.as_raw(),
|
||||
}
|
||||
impl From<ImageType> for ash::vk::ImageType {
|
||||
fn from(val: ImageType) -> Self {
|
||||
ash::vk::ImageType::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
Linear = LINEAR,
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum ImageTiling {
|
||||
Optimal = ash::vk::ImageTiling::OPTIMAL.as_raw(),
|
||||
Linear = ash::vk::ImageTiling::LINEAR.as_raw(),
|
||||
}
|
||||
|
||||
impl From<ImageTiling> for ash::vk::ImageTiling {
|
||||
fn from(val: ImageTiling) -> Self {
|
||||
ash::vk::ImageTiling::from_raw(val as i32)
|
||||
}
|
||||
/*
|
||||
// TODO: document
|
||||
DrmFormatModifier = DRM_FORMAT_MODIFIER_EXT {
|
||||
extensions: [ext_image_drm_format_modifier],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
/// The dimensions of an image.
|
||||
@ -716,7 +595,7 @@ pub struct ImageFormatInfo {
|
||||
|
||||
/// The `usage` that the image will have.
|
||||
///
|
||||
/// The default value is [`ImageUsage::none()`], which must be overridden.
|
||||
/// The default value is [`ImageUsage::empty()`], which must be overridden.
|
||||
pub usage: ImageUsage,
|
||||
|
||||
/// An external memory handle type that will be imported to or exported from the image.
|
||||
@ -724,8 +603,8 @@ pub struct ImageFormatInfo {
|
||||
/// This is needed to retrieve the
|
||||
/// [`external_memory_properties`](ImageFormatProperties::external_memory_properties) value,
|
||||
/// and the physical device API version must be at least 1.1 or the
|
||||
/// [`ext_filter_cubic`](crate::device::DeviceExtensions::ext_filter_cubic) extension must be
|
||||
/// supported on the physical device.
|
||||
/// [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
|
||||
/// extension must be enabled on the instance.
|
||||
///
|
||||
/// The default value is `None`.
|
||||
pub external_memory_handle_type: Option<ExternalMemoryHandleType>,
|
||||
@ -771,7 +650,7 @@ impl Default for ImageFormatInfo {
|
||||
format: None,
|
||||
image_type: ImageType::Dim2d,
|
||||
tiling: ImageTiling::Optimal,
|
||||
usage: ImageUsage::none(),
|
||||
usage: ImageUsage::empty(),
|
||||
external_memory_handle_type: None,
|
||||
image_view_type: None,
|
||||
mutable_format: false,
|
||||
|
@ -77,9 +77,9 @@ impl StorageImage {
|
||||
color_attachment: !is_depth,
|
||||
depth_stencil_attachment: is_depth,
|
||||
input_attachment: true,
|
||||
transient_attachment: false,
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
let flags = ImageCreateFlags::none();
|
||||
let flags = ImageCreateFlags::empty();
|
||||
|
||||
StorageImage::with_usage(device, dimensions, format, usage, flags, queue_families)
|
||||
}
|
||||
@ -176,7 +176,7 @@ impl StorageImage {
|
||||
},
|
||||
external_memory_handle_types: ExternalMemoryHandleTypes {
|
||||
opaque_fd: true,
|
||||
..ExternalMemoryHandleTypes::none()
|
||||
..ExternalMemoryHandleTypes::empty()
|
||||
},
|
||||
mutable_format: flags.mutable_format,
|
||||
cube_compatible: flags.cube_compatible,
|
||||
@ -225,7 +225,7 @@ impl StorageImage {
|
||||
height: size[1],
|
||||
array_layers: 1,
|
||||
};
|
||||
let flags = ImageCreateFlags::none();
|
||||
let flags = ImageCreateFlags::empty();
|
||||
let image_result = StorageImage::with_usage(
|
||||
queue.device().clone(),
|
||||
dims,
|
||||
@ -371,7 +371,7 @@ mod tests {
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
color_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
let img_view = StorageImage::general_purpose_image_view(
|
||||
queue,
|
||||
@ -389,7 +389,7 @@ mod tests {
|
||||
// Not valid for image view...
|
||||
let usage = ImageUsage {
|
||||
transfer_src: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
};
|
||||
let img_result = StorageImage::general_purpose_image_view(
|
||||
queue,
|
||||
|
@ -23,6 +23,7 @@ use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
format::{ChromaSampling, Format, FormatFeatures, NumericType},
|
||||
image::{view::ImageViewCreationError, ImageFormatInfo, ImageFormatProperties, ImageType},
|
||||
macros::ExtensionNotEnabled,
|
||||
memory::{
|
||||
DeviceMemory, DeviceMemoryAllocationError, ExternalMemoryHandleType,
|
||||
ExternalMemoryHandleTypes, MemoryRequirements,
|
||||
@ -202,8 +203,23 @@ impl UnsafeImage {
|
||||
|
||||
let format = format.unwrap(); // Can be None for "external formats" but Vulkano doesn't support that yet
|
||||
|
||||
// VUID-VkImageCreateInfo-format-parameter
|
||||
// TODO: format.validate(device)?;
|
||||
|
||||
// VUID-VkImageCreateInfo-samples-parameter
|
||||
samples.validate(device)?;
|
||||
|
||||
// VUID-VkImageCreateInfo-tiling-parameter
|
||||
tiling.validate(device)?;
|
||||
|
||||
// VUID-VkImageCreateInfo-usage-parameter
|
||||
usage.validate(device)?;
|
||||
|
||||
// VUID-VkImageCreateInfo-usage-requiredbitmask
|
||||
assert!(usage != ImageUsage::none());
|
||||
assert!(!usage.is_empty());
|
||||
|
||||
// VUID-VkImageCreateInfo-initialLayout-parameter
|
||||
initial_layout.validate(device)?;
|
||||
|
||||
if usage.transient_attachment {
|
||||
// VUID-VkImageCreateInfo-usage-00966
|
||||
@ -212,15 +228,14 @@ impl UnsafeImage {
|
||||
);
|
||||
|
||||
// VUID-VkImageCreateInfo-usage-00963
|
||||
assert!(
|
||||
ImageUsage {
|
||||
transient_attachment: false,
|
||||
color_attachment: false,
|
||||
depth_stencil_attachment: false,
|
||||
input_attachment: false,
|
||||
..usage
|
||||
} == ImageUsage::none()
|
||||
)
|
||||
assert!(ImageUsage {
|
||||
transient_attachment: false,
|
||||
color_attachment: false,
|
||||
depth_stencil_attachment: false,
|
||||
input_attachment: false,
|
||||
..usage
|
||||
}
|
||||
.is_empty())
|
||||
}
|
||||
|
||||
// VUID-VkImageCreateInfo-initialLayout-00993
|
||||
@ -492,6 +507,9 @@ impl UnsafeImage {
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter
|
||||
external_memory_handle_types.validate(device)?;
|
||||
|
||||
// VUID-VkImageCreateInfo-pNext-01443
|
||||
if initial_layout != ImageLayout::Undefined {
|
||||
return Err(ImageCreationError::ExternalMemoryInvalidInitialLayout);
|
||||
@ -557,7 +575,7 @@ impl UnsafeImage {
|
||||
if usage.color_attachment
|
||||
&& !device_properties
|
||||
.framebuffer_color_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
// TODO: how to handle framebuffer_integer_color_sample_counts limit, which only
|
||||
// exists >= Vulkan 1.2
|
||||
@ -570,7 +588,7 @@ impl UnsafeImage {
|
||||
if aspects.depth
|
||||
&& !device_properties
|
||||
.framebuffer_depth_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -578,7 +596,7 @@ impl UnsafeImage {
|
||||
if aspects.stencil
|
||||
&& !device_properties
|
||||
.framebuffer_stencil_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -590,7 +608,7 @@ impl UnsafeImage {
|
||||
NumericType::UINT | NumericType::SINT => {
|
||||
if !device_properties
|
||||
.sampled_image_integer_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -604,7 +622,7 @@ impl UnsafeImage {
|
||||
| NumericType::SRGB => {
|
||||
if !device_properties
|
||||
.sampled_image_color_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -616,7 +634,7 @@ impl UnsafeImage {
|
||||
if aspects.depth
|
||||
&& !device_properties
|
||||
.sampled_image_depth_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -624,7 +642,7 @@ impl UnsafeImage {
|
||||
if aspects.stencil
|
||||
&& device_properties
|
||||
.sampled_image_stencil_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -634,7 +652,7 @@ impl UnsafeImage {
|
||||
if usage.storage
|
||||
&& !device_properties
|
||||
.storage_image_sample_counts
|
||||
.contains(samples)
|
||||
.contains_count(samples)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -654,7 +672,7 @@ impl UnsafeImage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
..usage
|
||||
} == ImageUsage::none())
|
||||
}.is_empty())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -737,7 +755,7 @@ impl UnsafeImage {
|
||||
}
|
||||
|
||||
// VUID-VkImageCreateInfo-samples-02258
|
||||
if !sample_counts.contains(samples) {
|
||||
if !sample_counts.contains_count(samples) {
|
||||
return Err(ImageCreationError::SampleCountNotSupported {
|
||||
samples,
|
||||
supported: sample_counts,
|
||||
@ -777,7 +795,7 @@ impl UnsafeImage {
|
||||
cube_compatible,
|
||||
array_2d_compatible,
|
||||
block_texel_view_compatible,
|
||||
..ImageCreateFlags::none()
|
||||
..ImageCreateFlags::empty()
|
||||
};
|
||||
|
||||
let (image_type, extent, array_layers) = match dimensions {
|
||||
@ -869,15 +887,14 @@ impl UnsafeImage {
|
||||
.format_properties(format)
|
||||
.optimal_tiling_features;
|
||||
|
||||
assert!(
|
||||
ImageCreateFlags {
|
||||
mutable_format: false,
|
||||
cube_compatible: false,
|
||||
array_2d_compatible: false,
|
||||
block_texel_view_compatible: false,
|
||||
..ImageCreateFlags::none()
|
||||
} == ImageCreateFlags::none()
|
||||
);
|
||||
assert!(ImageCreateFlags {
|
||||
mutable_format: false,
|
||||
cube_compatible: false,
|
||||
array_2d_compatible: false,
|
||||
block_texel_view_compatible: false,
|
||||
..ImageCreateFlags::empty()
|
||||
}
|
||||
.is_empty());
|
||||
|
||||
// TODO: check that usage is correct in regard to `output`?
|
||||
|
||||
@ -1198,7 +1215,7 @@ impl UnsafeImage {
|
||||
if aspects.plane0 {
|
||||
ImageAspects {
|
||||
plane0: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
}
|
||||
} else {
|
||||
aspects
|
||||
@ -1425,7 +1442,7 @@ pub struct UnsafeImageCreateInfo {
|
||||
|
||||
/// How the image is going to be used.
|
||||
///
|
||||
/// The default value is [`ImageUsage::none()`], which must be overridden.
|
||||
/// The default value is [`ImageUsage::empty()`], which must be overridden.
|
||||
pub usage: ImageUsage,
|
||||
|
||||
/// Whether the image can be shared across multiple queues, or is limited to a single queue.
|
||||
@ -1445,7 +1462,7 @@ pub struct UnsafeImageCreateInfo {
|
||||
/// extension must be enabled, and `initial_layout` must be set to
|
||||
/// [`ImageLayout::Undefined`].
|
||||
///
|
||||
/// The default value is [`ExternalMemoryHandleTypes::none()`].
|
||||
/// The default value is [`ExternalMemoryHandleTypes::empty()`].
|
||||
pub external_memory_handle_types: ExternalMemoryHandleTypes,
|
||||
|
||||
/// For non-multi-planar formats, whether an image view wrapping the image can have a
|
||||
@ -1497,10 +1514,10 @@ impl Default for UnsafeImageCreateInfo {
|
||||
mip_levels: 1,
|
||||
samples: SampleCount::Sample1,
|
||||
tiling: ImageTiling::Optimal,
|
||||
usage: ImageUsage::none(),
|
||||
usage: ImageUsage::empty(),
|
||||
sharing: Sharing::Exclusive,
|
||||
initial_layout: ImageLayout::Undefined,
|
||||
external_memory_handle_types: ExternalMemoryHandleTypes::none(),
|
||||
external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
|
||||
mutable_format: false,
|
||||
cube_compatible: false,
|
||||
array_2d_compatible: false,
|
||||
@ -1789,6 +1806,16 @@ impl From<VulkanError> for ImageCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for ImageCreationError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the memory layout of an image with linear tiling.
|
||||
///
|
||||
/// Obtained by calling `*_linear_layout` on the image.
|
||||
@ -2218,7 +2245,7 @@ mod tests {
|
||||
format: Some(Format::R8G8B8A8_UNORM),
|
||||
usage: ImageUsage {
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2242,7 +2269,7 @@ mod tests {
|
||||
usage: ImageUsage {
|
||||
transient_attachment: true,
|
||||
color_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2267,7 +2294,7 @@ mod tests {
|
||||
mip_levels: 0,
|
||||
usage: ImageUsage {
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2291,7 +2318,7 @@ mod tests {
|
||||
mip_levels: u32::MAX,
|
||||
usage: ImageUsage {
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2319,7 +2346,7 @@ mod tests {
|
||||
samples: SampleCount::Sample2,
|
||||
usage: ImageUsage {
|
||||
storage: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2350,7 +2377,7 @@ mod tests {
|
||||
format: Some(Format::ASTC_5x4_UNORM_BLOCK),
|
||||
usage: ImageUsage {
|
||||
color_attachment: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2382,7 +2409,7 @@ mod tests {
|
||||
usage: ImageUsage {
|
||||
transient_attachment: true,
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
@ -2405,7 +2432,7 @@ mod tests {
|
||||
format: Some(Format::R8G8B8A8_UNORM),
|
||||
usage: ImageUsage {
|
||||
sampled: true,
|
||||
..ImageUsage::none()
|
||||
..ImageUsage::empty()
|
||||
},
|
||||
cube_compatible: true,
|
||||
..Default::default()
|
||||
@ -2428,7 +2455,7 @@ mod tests {
|
||||
depth: true,
|
||||
stencil: true,
|
||||
plane0: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
}
|
||||
.iter()
|
||||
.collect();
|
||||
@ -2446,7 +2473,7 @@ mod tests {
|
||||
depth: true,
|
||||
stencil: true,
|
||||
plane0: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
},
|
||||
mip_levels: 0..6,
|
||||
array_layers: 0..8,
|
||||
@ -2469,7 +2496,7 @@ mod tests {
|
||||
depth: true,
|
||||
stencil: false,
|
||||
plane0: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
},
|
||||
mip_levels: 0..6,
|
||||
array_layers: 0..8,
|
||||
@ -2493,7 +2520,7 @@ mod tests {
|
||||
depth: true,
|
||||
stencil: true,
|
||||
plane0: false,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
},
|
||||
mip_levels: 2..4,
|
||||
array_layers: 0..8,
|
||||
@ -2516,7 +2543,7 @@ mod tests {
|
||||
depth: false,
|
||||
stencil: false,
|
||||
plane0: false,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
},
|
||||
mip_levels: 0..1,
|
||||
array_layers: 2..4,
|
||||
@ -2542,7 +2569,7 @@ mod tests {
|
||||
depth: true,
|
||||
stencil: true,
|
||||
plane0: false,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
},
|
||||
mip_levels: 2..4,
|
||||
array_layers: 6..8,
|
||||
|
@ -108,7 +108,7 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
|
||||
if aspects.plane0 {
|
||||
ImageAspects {
|
||||
plane0: true,
|
||||
..ImageAspects::none()
|
||||
..ImageAspects::empty()
|
||||
}
|
||||
} else {
|
||||
aspects
|
||||
|
@ -7,231 +7,91 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::ops::BitOr;
|
||||
use crate::macros::vulkan_bitflags;
|
||||
|
||||
/// Describes how an image is going to be used. This is **not** just an optimization.
|
||||
///
|
||||
/// If you try to use an image in a way that you didn't declare, a panic will happen.
|
||||
///
|
||||
/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
|
||||
/// and `input_attachment` can be true as well. The rest must be false or an error will be returned
|
||||
/// when creating the image.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ImageUsage {
|
||||
/// Can be used as a source for transfers. Includes blits.
|
||||
pub transfer_src: bool,
|
||||
vulkan_bitflags! {
|
||||
/// Describes how an image is going to be used. This is **not** just an optimization.
|
||||
///
|
||||
/// If you try to use an image in a way that you didn't declare, an error will occur.
|
||||
#[non_exhaustive]
|
||||
ImageUsage = ImageUsageFlags(u32);
|
||||
|
||||
/// Can be used as a destination for transfers. Includes blits.
|
||||
pub transfer_dst: bool,
|
||||
/// The image can be used as a source for transfer, blit, resolve and clear commands.
|
||||
transfer_src = TRANSFER_SRC,
|
||||
|
||||
/// Can be sampled from a shader.
|
||||
pub sampled: bool,
|
||||
/// The image can be used as a destination for transfer, blit, resolve and clear commands.
|
||||
transfer_dst = TRANSFER_DST,
|
||||
|
||||
/// Can be used as an image storage in a shader.
|
||||
pub storage: bool,
|
||||
/// The image can be used as a sampled image in a shader.
|
||||
sampled = SAMPLED,
|
||||
|
||||
/// Can be attached as a color attachment to a framebuffer.
|
||||
pub color_attachment: bool,
|
||||
/// The image can be used as a storage image in a shader.
|
||||
storage = STORAGE,
|
||||
|
||||
/// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
|
||||
pub depth_stencil_attachment: bool,
|
||||
/// The image can be used as a color attachment in a render pass/framebuffer.
|
||||
color_attachment = COLOR_ATTACHMENT,
|
||||
|
||||
/// Indicates that this image will only ever be used as a temporary framebuffer attachment.
|
||||
/// The image can be used as a depth/stencil attachment in a render pass/framebuffer.
|
||||
depth_stencil_attachment = DEPTH_STENCIL_ATTACHMENT,
|
||||
|
||||
/// The image will be used as an attachment, and will only ever be used temporarily.
|
||||
/// As soon as you leave a render pass, the content of transient images becomes undefined.
|
||||
///
|
||||
/// This is a hint to the Vulkan implementation that it may not need allocate any memory for
|
||||
/// this image if the image can live entirely in some cache.
|
||||
pub transient_attachment: bool,
|
||||
|
||||
/// Can be used as an input attachment. In other words, you can draw to it in a subpass then
|
||||
/// read from it in a following pass.
|
||||
pub input_attachment: bool,
|
||||
}
|
||||
|
||||
impl ImageUsage {
|
||||
/// Builds a `ImageUsage` with all values set to true. Note that using the returned value will
|
||||
/// produce an error because of `transient_attachment` being true.
|
||||
#[inline]
|
||||
pub const fn all() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: true,
|
||||
transfer_dst: true,
|
||||
sampled: true,
|
||||
storage: true,
|
||||
color_attachment: true,
|
||||
depth_stencil_attachment: true,
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `ImageUsage` with all values set to false. Useful as a default value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use vulkano::image::ImageUsage as ImageUsage;
|
||||
///
|
||||
/// let _usage = ImageUsage {
|
||||
/// transfer_dst: true,
|
||||
/// sampled: true,
|
||||
/// .. ImageUsage::none()
|
||||
/// };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn none() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
sampled: false,
|
||||
storage: false,
|
||||
color_attachment: false,
|
||||
depth_stencil_attachment: false,
|
||||
transient_attachment: false,
|
||||
input_attachment: false,
|
||||
}
|
||||
}
|
||||
/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
|
||||
/// and `input_attachment` can be true as well. The rest must be false or an error will be
|
||||
/// returned when creating the image.
|
||||
transient_attachment = TRANSIENT_ATTACHMENT,
|
||||
|
||||
/// Builds a ImageUsage with color_attachment set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn color_attachment() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
sampled: false,
|
||||
storage: false,
|
||||
color_attachment: true,
|
||||
depth_stencil_attachment: false,
|
||||
transient_attachment: false,
|
||||
input_attachment: false,
|
||||
}
|
||||
}
|
||||
/// The image can be used as an input attachment in a render pass/framebuffer.
|
||||
input_attachment = INPUT_ATTACHMENT,
|
||||
|
||||
/// Builds a ImageUsage with depth_stencil_attachment set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn depth_stencil_attachment() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
sampled: false,
|
||||
storage: false,
|
||||
color_attachment: false,
|
||||
depth_stencil_attachment: true,
|
||||
transient_attachment: false,
|
||||
input_attachment: false,
|
||||
}
|
||||
}
|
||||
/*
|
||||
// TODO: document
|
||||
video_decode_dst = VIDEO_DECODE_DST_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
/// Builds a ImageUsage with color_attachment and transient_attachment set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn transient_color_attachment() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
sampled: false,
|
||||
storage: false,
|
||||
color_attachment: true,
|
||||
depth_stencil_attachment: false,
|
||||
transient_attachment: true,
|
||||
input_attachment: false,
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
video_decode_src = VIDEO_DECODE_SRC_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
/// Builds a ImageUsage with depth_stencil_attachment and transient_attachment set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn transient_depth_stencil_attachment() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
sampled: false,
|
||||
storage: false,
|
||||
color_attachment: false,
|
||||
depth_stencil_attachment: true,
|
||||
transient_attachment: true,
|
||||
input_attachment: false,
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
video_decode_dpb = VIDEO_DECODE_DPB_KHR {
|
||||
extensions: [khr_video_decode_queue],
|
||||
},
|
||||
|
||||
/// Builds a ImageUsage with input_attachment and transient_attachment set to true and the rest to false.
|
||||
#[inline]
|
||||
pub const fn transient_input_attachment() -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: false,
|
||||
transfer_dst: false,
|
||||
sampled: false,
|
||||
storage: false,
|
||||
color_attachment: false,
|
||||
depth_stencil_attachment: false,
|
||||
transient_attachment: true,
|
||||
input_attachment: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageUsage> for ash::vk::ImageUsageFlags {
|
||||
#[inline]
|
||||
fn from(val: ImageUsage) -> Self {
|
||||
let mut result = ash::vk::ImageUsageFlags::empty();
|
||||
if val.transfer_src {
|
||||
result |= ash::vk::ImageUsageFlags::TRANSFER_SRC;
|
||||
}
|
||||
if val.transfer_dst {
|
||||
result |= ash::vk::ImageUsageFlags::TRANSFER_DST;
|
||||
}
|
||||
if val.sampled {
|
||||
result |= ash::vk::ImageUsageFlags::SAMPLED;
|
||||
}
|
||||
if val.storage {
|
||||
result |= ash::vk::ImageUsageFlags::STORAGE;
|
||||
}
|
||||
if val.color_attachment {
|
||||
result |= ash::vk::ImageUsageFlags::COLOR_ATTACHMENT;
|
||||
}
|
||||
if val.depth_stencil_attachment {
|
||||
result |= ash::vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT;
|
||||
}
|
||||
if val.transient_attachment {
|
||||
result |= ash::vk::ImageUsageFlags::TRANSIENT_ATTACHMENT;
|
||||
}
|
||||
if val.input_attachment {
|
||||
result |= ash::vk::ImageUsageFlags::INPUT_ATTACHMENT;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::ImageUsageFlags> for ImageUsage {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::ImageUsageFlags) -> ImageUsage {
|
||||
ImageUsage {
|
||||
transfer_src: !(val & ash::vk::ImageUsageFlags::TRANSFER_SRC).is_empty(),
|
||||
transfer_dst: !(val & ash::vk::ImageUsageFlags::TRANSFER_DST).is_empty(),
|
||||
sampled: !(val & ash::vk::ImageUsageFlags::SAMPLED).is_empty(),
|
||||
storage: !(val & ash::vk::ImageUsageFlags::STORAGE).is_empty(),
|
||||
color_attachment: !(val & ash::vk::ImageUsageFlags::COLOR_ATTACHMENT).is_empty(),
|
||||
depth_stencil_attachment: !(val & ash::vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT)
|
||||
.is_empty(),
|
||||
transient_attachment: !(val & ash::vk::ImageUsageFlags::TRANSIENT_ATTACHMENT)
|
||||
.is_empty(),
|
||||
input_attachment: !(val & ash::vk::ImageUsageFlags::INPUT_ATTACHMENT).is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for ImageUsage {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
ImageUsage {
|
||||
transfer_src: self.transfer_src || rhs.transfer_src,
|
||||
transfer_dst: self.transfer_dst || rhs.transfer_dst,
|
||||
sampled: self.sampled || rhs.sampled,
|
||||
storage: self.storage || rhs.storage,
|
||||
color_attachment: self.color_attachment || rhs.color_attachment,
|
||||
depth_stencil_attachment: self.depth_stencil_attachment || rhs.depth_stencil_attachment,
|
||||
transient_attachment: self.transient_attachment || rhs.transient_attachment,
|
||||
input_attachment: self.input_attachment || rhs.input_attachment,
|
||||
}
|
||||
}
|
||||
// TODO: document
|
||||
fragment_density_map = FRAGMENT_DENSITY_MAP_EXT {
|
||||
extensions: [ext_fragment_density_map],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
fragment_shading_rate_attachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
|
||||
extensions: [khr_fragment_shading_rate],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
video_encode_dst = VIDEO_ENCODE_DST_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
video_encode_src = VIDEO_ENCODE_SRC_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
video_encode_dpb = VIDEO_ENCODE_DPB_KHR {
|
||||
extensions: [khr_video_encode_queue],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
invocation_mask = INVOCATION_MASK_HUAWEI {
|
||||
extensions: [huawei_invocation_mask],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
format::{ChromaSampling, Format, FormatFeatures},
|
||||
image::{ImageAspects, ImageTiling, ImageType, SampleCount},
|
||||
macros::{vulkan_enum, ExtensionNotEnabled},
|
||||
sampler::{ycbcr::SamplerYcbcrConversion, ComponentMapping},
|
||||
OomError, VulkanError, VulkanObject,
|
||||
};
|
||||
@ -142,6 +143,27 @@ where
|
||||
assert!(level_count != 0);
|
||||
assert!(layer_count != 0);
|
||||
|
||||
// VUID-VkImageViewCreateInfo-viewType-parameter
|
||||
view_type.validate(image.device())?;
|
||||
|
||||
// VUID-VkImageViewCreateInfo-format-parameter
|
||||
// TODO: format.validate(image.device())?;
|
||||
|
||||
// VUID-VkComponentMapping-r-parameter
|
||||
component_mapping.r.validate(image.device())?;
|
||||
|
||||
// VUID-VkComponentMapping-g-parameter
|
||||
component_mapping.g.validate(image.device())?;
|
||||
|
||||
// VUID-VkComponentMapping-b-parameter
|
||||
component_mapping.b.validate(image.device())?;
|
||||
|
||||
// VUID-VkComponentMapping-a-parameter
|
||||
component_mapping.a.validate(image.device())?;
|
||||
|
||||
// VUID-VkImageSubresourceRange-aspectMask-parameter
|
||||
subresource_range.aspects.validate(image.device())?;
|
||||
|
||||
{
|
||||
let ImageAspects {
|
||||
color,
|
||||
@ -154,6 +176,7 @@ where
|
||||
memory_plane0,
|
||||
memory_plane1,
|
||||
memory_plane2,
|
||||
_ne: _,
|
||||
} = subresource_range.aspects;
|
||||
|
||||
assert!(!(metadata || memory_plane0 || memory_plane1 || memory_plane2));
|
||||
@ -664,7 +687,7 @@ impl Default for ImageViewCreateInfo {
|
||||
format: None,
|
||||
component_mapping: ComponentMapping::identity(),
|
||||
subresource_range: ImageSubresourceRange {
|
||||
aspects: ImageAspects::none(),
|
||||
aspects: ImageAspects::empty(),
|
||||
array_layers: 0..0,
|
||||
mip_levels: 0..0,
|
||||
},
|
||||
@ -707,6 +730,10 @@ pub enum ImageViewCreationError {
|
||||
/// Allocating memory failed.
|
||||
OomError(OomError),
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
@ -808,101 +835,106 @@ impl Error for ImageViewCreationError {
|
||||
|
||||
impl fmt::Display for ImageViewCreationError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
Self::OomError(_) => write!(
|
||||
fmt,
|
||||
f,
|
||||
"allocating memory failed",
|
||||
),
|
||||
Self::ExtensionNotEnabled { extension, reason } => write!(
|
||||
f,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
),
|
||||
Self::FeatureNotEnabled { feature, reason } => {
|
||||
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
|
||||
write!(f, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
Self::Array2dCompatibleMultipleMipLevels => write!(
|
||||
fmt,
|
||||
f,
|
||||
"a 2D image view was requested from a 3D image, but a range of multiple mip levels was specified",
|
||||
),
|
||||
Self::ArrayLayersOutOfRange { .. } => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the specified range of array layers was not a subset of those in the image",
|
||||
),
|
||||
Self::BlockTexelViewCompatibleMultipleArrayLayers => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the image has the `block_texel_view_compatible` flag, but a range of multiple array layers was specified",
|
||||
),
|
||||
Self::BlockTexelViewCompatibleMultipleMipLevels => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the image has the `block_texel_view_compatible` flag, but a range of multiple mip levels was specified",
|
||||
),
|
||||
Self::BlockTexelViewCompatibleUncompressedIs3d => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the image has the `block_texel_view_compatible` flag, and an uncompressed format was requested, and the image view type was `Dim3d`",
|
||||
),
|
||||
Self::FormatChromaSubsamplingInvalidImageDimensions => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the requested format has chroma subsampling, but the width and/or height of the image was not a multiple of 2",
|
||||
),
|
||||
Self::FormatNotCompatible => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the requested format was not compatible with the image",
|
||||
),
|
||||
Self::FormatNotSupported => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the given format was not supported by the device"
|
||||
),
|
||||
Self::FormatRequiresSamplerYcbcrConversion { .. } => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the format requires a sampler YCbCr conversion, but none was provided",
|
||||
),
|
||||
Self::FormatUsageNotSupported { .. } => write!(
|
||||
fmt,
|
||||
f,
|
||||
"a requested usage flag was not supported by the given format"
|
||||
),
|
||||
Self::ImageAspectsNotCompatible { .. } => write!(
|
||||
fmt,
|
||||
f,
|
||||
"an aspect was selected that was not present in the image",
|
||||
),
|
||||
Self::ImageMissingUsage => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the image was not created with one of the required usages for image views",
|
||||
),
|
||||
Self::ImageNotArray2dCompatible => write!(
|
||||
fmt,
|
||||
f,
|
||||
"a 2D image view was requested from a 3D image, but the image was not created with the `array_2d_compatible` flag",
|
||||
),
|
||||
Self::ImageNotCubeCompatible => write!(
|
||||
fmt,
|
||||
f,
|
||||
"a cube image view type was requested, but the image was not created with the `cube_compatible` flag",
|
||||
),
|
||||
Self::ImageTypeNotCompatible => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the given image view type was not compatible with the type of the image",
|
||||
),
|
||||
Self::IncompatibleType => write!(
|
||||
fmt,
|
||||
f,
|
||||
"image view type is not compatible with image, array layers or mipmap levels",
|
||||
),
|
||||
Self::MipLevelsOutOfRange { .. } => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the specified range of mip levels was not a subset of those in the image",
|
||||
),
|
||||
Self::MultisamplingNot2d => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the image has multisampling enabled, but the image view type was not `Dim2d` or `Dim2dArray`",
|
||||
),
|
||||
Self::SamplerYcbcrConversionComponentMappingNotIdentity { .. } => write!(
|
||||
fmt,
|
||||
f,
|
||||
"sampler YCbCr conversion was enabled, but `component_mapping` was not the identity mapping",
|
||||
),
|
||||
Self::TypeCubeArrayNotMultipleOf6ArrayLayers => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the `CubeArray` image view type was specified, but the range of array layers did not have a size that is a multiple 6"
|
||||
),
|
||||
Self::TypeCubeNot6ArrayLayers => write!(
|
||||
fmt,
|
||||
f,
|
||||
"the `Cube` image view type was specified, but the range of array layers did not have a size of 6"
|
||||
),
|
||||
Self::TypeNonArrayedMultipleArrayLayers => write!(
|
||||
fmt,
|
||||
f,
|
||||
"a non-arrayed image view type was specified, but a range of multiple array layers was specified"
|
||||
)
|
||||
}
|
||||
@ -927,17 +959,41 @@ impl From<VulkanError> for ImageViewCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
/// The geometry type of an image view.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum ImageViewType {
|
||||
Dim1d = ash::vk::ImageViewType::TYPE_1D.as_raw(),
|
||||
Dim1dArray = ash::vk::ImageViewType::TYPE_1D_ARRAY.as_raw(),
|
||||
Dim2d = ash::vk::ImageViewType::TYPE_2D.as_raw(),
|
||||
Dim2dArray = ash::vk::ImageViewType::TYPE_2D_ARRAY.as_raw(),
|
||||
Dim3d = ash::vk::ImageViewType::TYPE_3D.as_raw(),
|
||||
Cube = ash::vk::ImageViewType::CUBE.as_raw(),
|
||||
CubeArray = ash::vk::ImageViewType::CUBE_ARRAY.as_raw(),
|
||||
impl From<ExtensionNotEnabled> for ImageViewCreationError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_enum! {
|
||||
/// The geometry type of an image view.
|
||||
#[non_exhaustive]
|
||||
ImageViewType = ImageViewType(i32);
|
||||
|
||||
// TODO: document
|
||||
Dim1d = TYPE_1D,
|
||||
|
||||
// TODO: document
|
||||
Dim2d = TYPE_2D,
|
||||
|
||||
// TODO: document
|
||||
Dim3d = TYPE_3D,
|
||||
|
||||
// TODO: document
|
||||
Cube = CUBE,
|
||||
|
||||
// TODO: document
|
||||
Dim1dArray = TYPE_1D_ARRAY,
|
||||
|
||||
// TODO: document
|
||||
Dim2dArray = TYPE_2D_ARRAY,
|
||||
|
||||
// TODO: document
|
||||
CubeArray = CUBE_ARRAY,
|
||||
}
|
||||
|
||||
impl ImageViewType {
|
||||
@ -969,12 +1025,6 @@ impl ImageViewType {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ImageViewType> for ash::vk::ImageViewType {
|
||||
fn from(val: ImageViewType) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for types that represent the GPU can access an image view.
|
||||
pub unsafe trait ImageViewAbstract:
|
||||
VulkanObject<Object = ash::vk::ImageView> + DeviceOwned + fmt::Debug + Send + Sync
|
||||
|
@ -43,7 +43,7 @@
|
||||
//!
|
||||
|
||||
use super::Instance;
|
||||
use crate::{VulkanError, VulkanObject};
|
||||
use crate::{macros::vulkan_bitflags, VulkanError, VulkanObject};
|
||||
use std::{
|
||||
error::Error,
|
||||
ffi::{c_void, CStr},
|
||||
@ -108,11 +108,17 @@ impl DebugUtilsMessenger {
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
|
||||
// TODO: message_severity.validate()?;
|
||||
|
||||
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
|
||||
assert!(message_severity != DebugUtilsMessageSeverity::none());
|
||||
assert!(!message_severity.is_empty());
|
||||
|
||||
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
|
||||
// TODO: message_type.validate()?;
|
||||
|
||||
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
|
||||
assert!(message_type != DebugUtilsMessageType::none());
|
||||
assert!(!message_type.is_empty());
|
||||
|
||||
// VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
|
||||
// Can't be checked, creation is unsafe.
|
||||
@ -296,8 +302,15 @@ impl DebugUtilsMessengerCreateInfo {
|
||||
#[inline]
|
||||
pub fn user_callback(user_callback: UserCallback) -> Self {
|
||||
Self {
|
||||
message_severity: DebugUtilsMessageSeverity::errors_and_warnings(),
|
||||
message_type: DebugUtilsMessageType::general(),
|
||||
message_severity: DebugUtilsMessageSeverity {
|
||||
error: true,
|
||||
warning: true,
|
||||
..DebugUtilsMessageSeverity::empty()
|
||||
},
|
||||
message_type: DebugUtilsMessageType {
|
||||
general: true,
|
||||
..DebugUtilsMessageType::empty()
|
||||
},
|
||||
user_callback,
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
@ -332,234 +345,37 @@ pub struct Message<'a> {
|
||||
pub description: &'a str,
|
||||
}
|
||||
|
||||
/// Severity of message.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct DebugUtilsMessageSeverity {
|
||||
vulkan_bitflags! {
|
||||
/// Severity of message.
|
||||
#[non_exhaustive]
|
||||
DebugUtilsMessageSeverity = DebugUtilsMessageSeverityFlagsEXT(u32);
|
||||
|
||||
/// An error that may cause undefined results, including an application crash.
|
||||
pub error: bool,
|
||||
error = ERROR,
|
||||
|
||||
/// An unexpected use.
|
||||
pub warning: bool,
|
||||
warning = WARNING,
|
||||
|
||||
/// An informational message that may be handy when debugging an application.
|
||||
pub information: bool,
|
||||
information = INFO,
|
||||
|
||||
/// Diagnostic information from the loader and layers.
|
||||
pub verbose: bool,
|
||||
verbose = VERBOSE,
|
||||
}
|
||||
|
||||
impl DebugUtilsMessageSeverity {
|
||||
/// Builds a `MessageSeverity` with all fields set to `false` expect `error`.
|
||||
#[inline]
|
||||
pub const fn errors() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
error: true,
|
||||
..DebugUtilsMessageSeverity::none()
|
||||
}
|
||||
}
|
||||
vulkan_bitflags! {
|
||||
/// Type of message.
|
||||
#[non_exhaustive]
|
||||
DebugUtilsMessageType = DebugUtilsMessageTypeFlagsEXT(u32);
|
||||
|
||||
/// Builds a `MessageSeverity` with all fields set to `false` expect `warning`.
|
||||
#[inline]
|
||||
pub const fn warnings() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
warning: true,
|
||||
..DebugUtilsMessageSeverity::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageSeverity` with all fields set to `false` expect `information`.
|
||||
#[inline]
|
||||
pub const fn information() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
information: true,
|
||||
..DebugUtilsMessageSeverity::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`.
|
||||
#[inline]
|
||||
pub const fn verbose() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
verbose: true,
|
||||
..DebugUtilsMessageSeverity::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageSeverity` with all fields set to `false` expect `error`, `warning`
|
||||
/// and `performance_warning`.
|
||||
#[inline]
|
||||
pub const fn errors_and_warnings() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
error: true,
|
||||
warning: true,
|
||||
..DebugUtilsMessageSeverity::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageSeverity` with all fields set to `false`.
|
||||
#[inline]
|
||||
pub const fn none() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
error: false,
|
||||
warning: false,
|
||||
information: false,
|
||||
verbose: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageSeverity` with all fields set to `true`.
|
||||
#[inline]
|
||||
pub const fn all() -> DebugUtilsMessageSeverity {
|
||||
DebugUtilsMessageSeverity {
|
||||
error: true,
|
||||
warning: true,
|
||||
information: true,
|
||||
verbose: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for DebugUtilsMessageSeverity {
|
||||
type Output = Self;
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
DebugUtilsMessageSeverity {
|
||||
error: self.error | rhs.error,
|
||||
warning: self.warning | rhs.warning,
|
||||
information: self.information | rhs.information,
|
||||
verbose: self.verbose | rhs.verbose,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DebugUtilsMessageSeverity> for ash::vk::DebugUtilsMessageSeverityFlagsEXT {
|
||||
#[inline]
|
||||
fn from(val: DebugUtilsMessageSeverity) -> Self {
|
||||
let mut result = Self::empty();
|
||||
if val.information {
|
||||
result |= Self::INFO;
|
||||
}
|
||||
if val.warning {
|
||||
result |= Self::WARNING;
|
||||
}
|
||||
if val.error {
|
||||
result |= Self::ERROR;
|
||||
}
|
||||
if val.verbose {
|
||||
result |= Self::VERBOSE;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::DebugUtilsMessageSeverityFlagsEXT> for DebugUtilsMessageSeverity {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::DebugUtilsMessageSeverityFlagsEXT) -> Self {
|
||||
Self {
|
||||
information: val.intersects(ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO),
|
||||
warning: val.intersects(ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING),
|
||||
error: val.intersects(ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR),
|
||||
verbose: val.intersects(ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of message.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct DebugUtilsMessageType {
|
||||
/// Specifies that some general event has occurred.
|
||||
pub general: bool,
|
||||
general = GENERAL,
|
||||
|
||||
/// Specifies that something has occurred during validation against the vulkan specification
|
||||
pub validation: bool,
|
||||
validation = VALIDATION,
|
||||
|
||||
/// Specifies a potentially non-optimal use of Vulkan
|
||||
pub performance: bool,
|
||||
}
|
||||
|
||||
impl DebugUtilsMessageType {
|
||||
/// Builds a `MessageType` with general field set to `true`.
|
||||
#[inline]
|
||||
pub const fn general() -> DebugUtilsMessageType {
|
||||
DebugUtilsMessageType {
|
||||
general: true,
|
||||
validation: false,
|
||||
performance: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageType` with validation field set to `true`.
|
||||
#[inline]
|
||||
pub const fn validation() -> DebugUtilsMessageType {
|
||||
DebugUtilsMessageType {
|
||||
general: false,
|
||||
validation: true,
|
||||
performance: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageType` with performance field set to `true`.
|
||||
#[inline]
|
||||
pub const fn performance() -> DebugUtilsMessageType {
|
||||
DebugUtilsMessageType {
|
||||
general: false,
|
||||
validation: false,
|
||||
performance: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageType` with all fields set to `true`.
|
||||
#[inline]
|
||||
pub const fn all() -> DebugUtilsMessageType {
|
||||
DebugUtilsMessageType {
|
||||
general: true,
|
||||
validation: true,
|
||||
performance: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `MessageType` with all fields set to `false`.
|
||||
#[inline]
|
||||
pub const fn none() -> DebugUtilsMessageType {
|
||||
DebugUtilsMessageType {
|
||||
general: false,
|
||||
validation: false,
|
||||
performance: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for DebugUtilsMessageType {
|
||||
type Output = Self;
|
||||
fn bitor(self, rhs: Self) -> Self::Output {
|
||||
DebugUtilsMessageType {
|
||||
general: self.general | rhs.general,
|
||||
validation: self.validation | rhs.validation,
|
||||
performance: self.performance | rhs.performance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DebugUtilsMessageType> for ash::vk::DebugUtilsMessageTypeFlagsEXT {
|
||||
#[inline]
|
||||
fn from(val: DebugUtilsMessageType) -> Self {
|
||||
let mut result = Self::empty();
|
||||
if val.general {
|
||||
result |= Self::GENERAL;
|
||||
}
|
||||
if val.validation {
|
||||
result |= Self::VALIDATION;
|
||||
}
|
||||
if val.performance {
|
||||
result |= Self::PERFORMANCE;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::DebugUtilsMessageTypeFlagsEXT> for DebugUtilsMessageType {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::DebugUtilsMessageTypeFlagsEXT) -> Self {
|
||||
Self {
|
||||
general: val.intersects(ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL),
|
||||
validation: val.intersects(ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION),
|
||||
performance: val.intersects(ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE),
|
||||
}
|
||||
}
|
||||
performance = PERFORMANCE,
|
||||
}
|
||||
|
||||
/// A label to associate with a span of work in a queue.
|
||||
@ -608,8 +424,13 @@ mod tests {
|
||||
DebugUtilsMessenger::new(
|
||||
instance,
|
||||
DebugUtilsMessengerCreateInfo {
|
||||
message_severity: DebugUtilsMessageSeverity::none(),
|
||||
message_type: DebugUtilsMessageType::all(),
|
||||
message_severity: DebugUtilsMessageSeverity::empty(),
|
||||
message_type: DebugUtilsMessageType {
|
||||
general: true,
|
||||
validation: true,
|
||||
performance: true,
|
||||
..DebugUtilsMessageType::empty()
|
||||
},
|
||||
..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|_| {}))
|
||||
},
|
||||
)
|
||||
|
@ -11,7 +11,7 @@ pub use crate::{
|
||||
extensions::{ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements},
|
||||
Version,
|
||||
};
|
||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not, Sub, SubAssign};
|
||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign};
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
fmt::Formatter,
|
||||
@ -27,7 +27,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn empty_extensions() {
|
||||
let i: Vec<CString> = (&InstanceExtensions::none()).into();
|
||||
let i: Vec<CString> = (&InstanceExtensions::empty()).into();
|
||||
assert!(i.get(0).is_none());
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ use self::debug::{DebugUtilsMessengerCreateInfo, UserCallback};
|
||||
pub use self::{extensions::InstanceExtensions, layers::LayerProperties};
|
||||
use crate::{
|
||||
device::physical::{init_physical_devices, PhysicalDeviceInfo},
|
||||
instance::debug::{trampoline, DebugUtilsMessageSeverity, DebugUtilsMessageType},
|
||||
instance::debug::trampoline,
|
||||
OomError, VulkanError, VulkanLibrary, VulkanObject,
|
||||
};
|
||||
pub use crate::{
|
||||
@ -167,7 +167,7 @@ mod layers;
|
||||
/// let extensions = InstanceExtensions {
|
||||
/// khr_surface: true,
|
||||
/// khr_android_surface: true,
|
||||
/// .. InstanceExtensions::none()
|
||||
/// .. InstanceExtensions::empty()
|
||||
/// };
|
||||
///
|
||||
/// let instance = Instance::new(
|
||||
@ -393,10 +393,10 @@ impl Instance {
|
||||
}
|
||||
|
||||
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
|
||||
assert!(message_severity != DebugUtilsMessageSeverity::none());
|
||||
assert!(!message_severity.is_empty());
|
||||
|
||||
// VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
|
||||
assert!(message_type != DebugUtilsMessageType::none());
|
||||
assert!(!message_type.is_empty());
|
||||
|
||||
// VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
|
||||
// Can't be checked, creation is unsafe.
|
||||
@ -581,7 +581,7 @@ pub struct InstanceCreateInfo {
|
||||
|
||||
/// The extensions to enable on the instance.
|
||||
///
|
||||
/// The default value is [`InstanceExtensions::none()`].
|
||||
/// The default value is [`InstanceExtensions::empty()`].
|
||||
pub enabled_extensions: InstanceExtensions,
|
||||
|
||||
/// The layers to enable on the instance.
|
||||
@ -630,7 +630,7 @@ impl Default for InstanceCreateInfo {
|
||||
Self {
|
||||
application_name: None,
|
||||
application_version: Version::major_minor(0, 0),
|
||||
enabled_extensions: InstanceExtensions::none(),
|
||||
enabled_extensions: InstanceExtensions::empty(),
|
||||
enabled_layers: Vec::new(),
|
||||
engine_name: None,
|
||||
engine_version: Version::major_minor(0, 0),
|
||||
|
@ -104,6 +104,7 @@ mod fns;
|
||||
pub mod image;
|
||||
pub mod instance;
|
||||
pub mod library;
|
||||
mod macros;
|
||||
pub mod memory;
|
||||
pub mod pipeline;
|
||||
pub mod query;
|
||||
|
649
vulkano/src/macros.rs
Normal file
649
vulkano/src/macros.rs
Normal file
@ -0,0 +1,649 @@
|
||||
// Copyright (c) 2022 The Vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
macro_rules! vulkan_bitflags {
|
||||
{
|
||||
$(#[doc = $ty_doc:literal])*
|
||||
$ty:ident = $ty_ffi:ident($repr:ty);
|
||||
|
||||
$(
|
||||
$(#[doc = $flag_doc:literal])*
|
||||
$flag_name:ident = $flag_name_ffi:ident
|
||||
$({
|
||||
$(api_version: $api_version:ident,)?
|
||||
extensions: [$($extension:ident),+ $(,)?],
|
||||
})?
|
||||
,
|
||||
)+
|
||||
} => {
|
||||
$(#[doc = $ty_doc])*
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct $ty {
|
||||
$(
|
||||
$(#[doc = $flag_doc])*
|
||||
pub $flag_name: bool,
|
||||
)+
|
||||
}
|
||||
|
||||
impl $ty {
|
||||
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: false,
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
|
||||
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
|
||||
#[inline]
|
||||
pub const fn none() -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
|
||||
#[doc = concat!("Returns a `", stringify!($ty), "` with all of the flags set.")]
|
||||
#[inline]
|
||||
pub const fn all() -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: true,
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether no flags are set in `self`.
|
||||
#[inline]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
!(
|
||||
$(
|
||||
self.$flag_name
|
||||
)||+
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether any flags are set in both `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersects(&self, other: &Self) -> bool {
|
||||
$(
|
||||
(self.$flag_name && other.$flag_name)
|
||||
)||+
|
||||
}
|
||||
|
||||
/// Returns whether all flags in `other` are set in `self`.
|
||||
#[inline]
|
||||
pub const fn contains(&self, other: &Self) -> bool {
|
||||
$(
|
||||
(self.$flag_name || !other.$flag_name)
|
||||
)&&+
|
||||
}
|
||||
|
||||
/// Returns the union of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn union(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name || other.$flag_name),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the intersection of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersection(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name && other.$flag_name),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `self` without the flags set in `other`.
|
||||
#[inline]
|
||||
pub const fn difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name && !other.$flag_name),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the flags set in `self` or `other`, but not both.
|
||||
#[inline]
|
||||
pub const fn symmetric_difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name ^ other.$flag_name),
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the flags not in `self`.
|
||||
#[inline]
|
||||
pub const fn complement(&self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: !self.$flag_name,
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn validate(
|
||||
self,
|
||||
#[allow(unused_variables)] device: &crate::device::Device
|
||||
) -> Result<(), crate::macros::ExtensionNotEnabled> {
|
||||
$(
|
||||
$(
|
||||
if self.$flag_name && !(
|
||||
$(
|
||||
device.api_version() >= crate::Version::$api_version ||
|
||||
)?
|
||||
$(
|
||||
device.enabled_extensions().$extension
|
||||
)||+
|
||||
) {
|
||||
return Err(crate::macros::ExtensionNotEnabled {
|
||||
extension: stringify!($($extension)?),
|
||||
reason: concat!(stringify!($ty), "::", stringify!($flag_name), " was used"),
|
||||
});
|
||||
}
|
||||
)?
|
||||
)+
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$ty> for ash::vk::$ty_ffi {
|
||||
#[inline]
|
||||
fn from(val: $ty) -> Self {
|
||||
let mut result = ash::vk::$ty_ffi::empty();
|
||||
$(
|
||||
if val.$flag_name { result |= ash::vk::$ty_ffi::$flag_name_ffi }
|
||||
)+
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::$ty_ffi> for $ty {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::$ty_ffi) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: val.intersects(ash::vk::$ty_ffi::$flag_name_ffi),
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $ty {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: false,
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAnd for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitand(self, rhs: Self) -> Self {
|
||||
self.intersection(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAndAssign for $ty {
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
*self = self.intersection(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
self.union(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOrAssign for $ty {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = self.union(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitXor for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitxor(self, rhs: Self) -> Self {
|
||||
self.symmetric_difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitXorAssign for $ty {
|
||||
#[inline]
|
||||
fn bitxor_assign(&mut self, rhs: Self) {
|
||||
*self = self.symmetric_difference(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
self.difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for $ty {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = self.difference(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Not for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn not(self) -> Self {
|
||||
self.complement()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
$(#[doc = $ty_doc:literal])*
|
||||
#[non_exhaustive]
|
||||
$ty:ident = $ty_ffi:ident($repr:ty);
|
||||
|
||||
$(
|
||||
$(#[doc = $flag_doc:literal])*
|
||||
$flag_name:ident = $flag_name_ffi:ident
|
||||
$({
|
||||
$(api_version: $api_version:ident,)?
|
||||
extensions: [$($extension:ident),+ $(,)?],
|
||||
})?
|
||||
,
|
||||
)+
|
||||
} => {
|
||||
$(#[doc = $ty_doc])*
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct $ty {
|
||||
$(
|
||||
$(#[doc = $flag_doc])*
|
||||
pub $flag_name: bool,
|
||||
)+
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl $ty {
|
||||
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: false,
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
|
||||
#[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
|
||||
#[inline]
|
||||
pub const fn none() -> Self {
|
||||
Self::empty()
|
||||
}
|
||||
|
||||
/// Returns whether no flags are set in `self`.
|
||||
#[inline]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
!(
|
||||
$(
|
||||
self.$flag_name
|
||||
)||+
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether any flags are set in both `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersects(&self, other: &Self) -> bool {
|
||||
$(
|
||||
(self.$flag_name && other.$flag_name)
|
||||
)||+
|
||||
}
|
||||
|
||||
/// Returns whether all flags in `other` are set in `self`.
|
||||
#[inline]
|
||||
pub const fn contains(&self, other: &Self) -> bool {
|
||||
$(
|
||||
(self.$flag_name || !other.$flag_name)
|
||||
)&&+
|
||||
}
|
||||
|
||||
/// Returns the union of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn union(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name || other.$flag_name),
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the intersection of `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn intersection(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name && other.$flag_name),
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `self` without the flags set in `other`.
|
||||
#[inline]
|
||||
pub const fn difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name ^ other.$flag_name),
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the flags set in `self` or `other`, but not both.
|
||||
#[inline]
|
||||
pub const fn symmetric_difference(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: (self.$flag_name ^ other.$flag_name),
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn validate(
|
||||
self,
|
||||
#[allow(unused_variables)] device: &crate::device::Device
|
||||
) -> Result<(), crate::macros::ExtensionNotEnabled> {
|
||||
$(
|
||||
$(
|
||||
if self.$flag_name && !(
|
||||
$(
|
||||
device.api_version() >= crate::Version::$api_version ||
|
||||
)?
|
||||
$(
|
||||
device.enabled_extensions().$extension
|
||||
)||+
|
||||
) {
|
||||
return Err(crate::macros::ExtensionNotEnabled {
|
||||
extension: stringify!($($extension)?),
|
||||
reason: concat!(stringify!($ty), "::", stringify!($flag_name), " was used"),
|
||||
});
|
||||
}
|
||||
)?
|
||||
)+
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$ty> for ash::vk::$ty_ffi {
|
||||
#[inline]
|
||||
fn from(val: $ty) -> Self {
|
||||
let mut result = ash::vk::$ty_ffi::empty();
|
||||
$(
|
||||
if val.$flag_name { result |= ash::vk::$ty_ffi::$flag_name_ffi }
|
||||
)+
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::$ty_ffi> for $ty {
|
||||
#[inline]
|
||||
fn from(val: ash::vk::$ty_ffi) -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: val.intersects(ash::vk::$ty_ffi::$flag_name_ffi),
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $ty {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
$(
|
||||
$flag_name: false,
|
||||
)+
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAnd for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitand(self, rhs: Self) -> Self {
|
||||
self.intersection(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitAndAssign for $ty {
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, rhs: Self) {
|
||||
*self = self.intersection(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
self.union(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOrAssign for $ty {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: Self) {
|
||||
*self = self.union(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitXor for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitxor(self, rhs: Self) -> Self {
|
||||
self.symmetric_difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitXorAssign for $ty {
|
||||
#[inline]
|
||||
fn bitxor_assign(&mut self, rhs: Self) {
|
||||
*self = self.symmetric_difference(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for $ty {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
self.difference(&rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::SubAssign for $ty {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: Self) {
|
||||
*self = self.difference(&rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! vulkan_enum {
|
||||
{
|
||||
$(#[doc = $ty_doc:literal])*
|
||||
$ty:ident = $ty_ffi:ident($repr:ty);
|
||||
|
||||
$(
|
||||
$(#[doc = $flag_doc:literal])*
|
||||
$flag_name:ident = $flag_name_ffi:ident
|
||||
$({
|
||||
$(api_version: $api_version:ident,)?
|
||||
extensions: [$($extension:ident),+ $(,)?],
|
||||
})?
|
||||
,
|
||||
)+
|
||||
} => {
|
||||
$(#[doc = $ty_doc])*
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[repr($repr)]
|
||||
pub enum $ty {
|
||||
$(
|
||||
$(#[doc = $flag_doc])*
|
||||
$flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
|
||||
)+
|
||||
}
|
||||
|
||||
impl From<$ty> for ash::vk::$ty_ffi {
|
||||
#[inline]
|
||||
fn from(val: $ty) -> Self {
|
||||
ash::vk::$ty_ffi::from_raw(val as $repr)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ash::vk::$ty_ffi> for $ty {
|
||||
type Error = ();
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
|
||||
Ok(match val {
|
||||
$(
|
||||
ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
|
||||
)+
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
$(#[doc = $ty_doc:literal])*
|
||||
#[non_exhaustive]
|
||||
$ty:ident = $ty_ffi:ident($repr:ty);
|
||||
|
||||
$(
|
||||
$(#[doc = $flag_doc:literal])*
|
||||
$flag_name:ident = $flag_name_ffi:ident
|
||||
$({
|
||||
$(api_version: $api_version:ident,)?
|
||||
extensions: [$($extension:ident),+ $(,)?],
|
||||
})?
|
||||
,
|
||||
)+
|
||||
} => {
|
||||
$(#[doc = $ty_doc])*
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
#[repr($repr)]
|
||||
pub enum $ty {
|
||||
$(
|
||||
$(#[doc = $flag_doc])*
|
||||
$flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
|
||||
)+
|
||||
}
|
||||
|
||||
impl $ty {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn validate(
|
||||
self,
|
||||
#[allow(unused_variables)] device: &crate::device::Device
|
||||
) -> Result<(), crate::macros::ExtensionNotEnabled> {
|
||||
match self {
|
||||
$(
|
||||
$(
|
||||
Self::$flag_name => {
|
||||
if !(
|
||||
$(
|
||||
device.api_version() >= crate::Version::$api_version ||
|
||||
)?
|
||||
$(
|
||||
device.enabled_extensions().$extension
|
||||
)||+
|
||||
) {
|
||||
return Err(crate::macros::ExtensionNotEnabled {
|
||||
extension: stringify!($($extension)?),
|
||||
reason: concat!(stringify!($ty), "::", stringify!($flag_name), " was used"),
|
||||
});
|
||||
}
|
||||
},
|
||||
)?
|
||||
)+
|
||||
_ => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$ty> for ash::vk::$ty_ffi {
|
||||
#[inline]
|
||||
fn from(val: $ty) -> Self {
|
||||
ash::vk::$ty_ffi::from_raw(val as $repr)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ash::vk::$ty_ffi> for $ty {
|
||||
type Error = ();
|
||||
|
||||
#[inline]
|
||||
fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
|
||||
Ok(match val {
|
||||
$(
|
||||
ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
|
||||
)+
|
||||
_ => return Err(()),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use {vulkan_bitflags, vulkan_enum};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct ExtensionNotEnabled {
|
||||
pub(crate) extension: &'static str,
|
||||
pub(crate) reason: &'static str,
|
||||
}
|
@ -10,6 +10,7 @@
|
||||
use super::DedicatedAllocation;
|
||||
use crate::{
|
||||
device::{physical::MemoryType, Device, DeviceOwned},
|
||||
macros::{vulkan_bitflags, vulkan_enum, ExtensionNotEnabled},
|
||||
DeviceSize, OomError, Version, VulkanError, VulkanObject,
|
||||
};
|
||||
use std::{
|
||||
@ -19,7 +20,7 @@ use std::{
|
||||
fs::File,
|
||||
hash::{Hash, Hasher},
|
||||
mem::MaybeUninit,
|
||||
ops::{BitOr, Range},
|
||||
ops::Range,
|
||||
ptr, slice,
|
||||
sync::Arc,
|
||||
};
|
||||
@ -215,24 +216,24 @@ impl DeviceMemory {
|
||||
}
|
||||
}
|
||||
|
||||
// VUID-VkMemoryAllocateInfo-pNext-00639
|
||||
// VUID-VkExportMemoryAllocateInfo-handleTypes-00656
|
||||
// TODO: how do you fullfill this when you don't know the image or buffer parameters?
|
||||
// Does exporting memory require specifying these parameters up front, and does it tie the
|
||||
// allocation to only images or buffers of that type?
|
||||
if !export_handle_types.is_empty() {
|
||||
if !(device.api_version() >= Version::V1_1
|
||||
|| device.enabled_extensions().khr_external_memory)
|
||||
{
|
||||
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
|
||||
extension: "khr_external_memory_fd",
|
||||
reason: "`import_info` was `MemoryImportInfo::Fd`",
|
||||
});
|
||||
}
|
||||
|
||||
if export_handle_types.opaque_fd && !device.enabled_extensions().khr_external_memory_fd {
|
||||
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
|
||||
extension: "khr_external_memory_fd",
|
||||
reason: "`export_handle_types.opaque_fd` was set",
|
||||
});
|
||||
}
|
||||
// VUID-VkExportMemoryAllocateInfo-handleTypes-parameter
|
||||
export_handle_types.validate(device)?;
|
||||
|
||||
if export_handle_types.dma_buf && !device.enabled_extensions().ext_external_memory_dma_buf {
|
||||
return Err(DeviceMemoryAllocationError::ExtensionNotEnabled {
|
||||
extension: "ext_external_memory_dma_buf",
|
||||
reason: "`export_handle_types.dma_buf` was set",
|
||||
});
|
||||
// VUID-VkMemoryAllocateInfo-pNext-00639
|
||||
// VUID-VkExportMemoryAllocateInfo-handleTypes-00656
|
||||
// TODO: how do you fullfill this when you don't know the image or buffer parameters?
|
||||
// Does exporting memory require specifying these parameters up front, and does it tie the
|
||||
// allocation to only images or buffers of that type?
|
||||
}
|
||||
|
||||
if let Some(import_info) = import_info {
|
||||
@ -258,6 +259,9 @@ impl DeviceMemory {
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// VUID-VkImportMemoryFdInfoKHR-handleType-parameter
|
||||
handle_type.validate(device)?;
|
||||
|
||||
// VUID-VkImportMemoryFdInfoKHR-handleType-00669
|
||||
match handle_type {
|
||||
ExternalMemoryHandleType::OpaqueFd => {
|
||||
@ -312,6 +316,9 @@ impl DeviceMemory {
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
// VUID-VkImportMemoryWin32HandleInfoKHR-handleType-parameter
|
||||
handle_type.validate(device)?;
|
||||
|
||||
// VUID-VkImportMemoryWin32HandleInfoKHR-handleType-00660
|
||||
match handle_type {
|
||||
ExternalMemoryHandleType::OpaqueWin32
|
||||
@ -376,7 +383,7 @@ impl DeviceMemory {
|
||||
allocate_info = allocate_info.push_next(info);
|
||||
}
|
||||
|
||||
let mut export_allocate_info = if export_handle_types != ExternalMemoryHandleTypes::none() {
|
||||
let mut export_allocate_info = if !export_handle_types.is_empty() {
|
||||
Some(ash::vk::ExportMemoryAllocateInfo {
|
||||
handle_types: export_handle_types.into(),
|
||||
..Default::default()
|
||||
@ -483,6 +490,9 @@ impl DeviceMemory {
|
||||
&self,
|
||||
handle_type: ExternalMemoryHandleType,
|
||||
) -> Result<std::fs::File, DeviceMemoryExportError> {
|
||||
// VUID-VkMemoryGetFdInfoKHR-handleType-parameter
|
||||
handle_type.validate(&self.device)?;
|
||||
|
||||
// VUID-VkMemoryGetFdInfoKHR-handleType-00672
|
||||
if !matches!(
|
||||
handle_type,
|
||||
@ -728,6 +738,16 @@ impl From<MemoryMapError> for DeviceMemoryAllocationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for DeviceMemoryAllocationError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters to allocate a new `DeviceMemory`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MemoryAllocateInfo<'d> {
|
||||
@ -762,7 +782,7 @@ impl Default for MemoryAllocateInfo<'static> {
|
||||
allocation_size: 0,
|
||||
memory_type_index: u32::MAX,
|
||||
dedicated_allocation: None,
|
||||
export_handle_types: ExternalMemoryHandleTypes::none(),
|
||||
export_handle_types: ExternalMemoryHandleTypes::empty(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -775,7 +795,7 @@ impl<'d> MemoryAllocateInfo<'d> {
|
||||
allocation_size: 0,
|
||||
memory_type_index: u32::MAX,
|
||||
dedicated_allocation: Some(dedicated_allocation),
|
||||
export_handle_types: ExternalMemoryHandleTypes::none(),
|
||||
export_handle_types: ExternalMemoryHandleTypes::empty(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
@ -834,128 +854,125 @@ pub enum MemoryImportInfo {
|
||||
},
|
||||
}
|
||||
|
||||
/// Describes a handle type used for Vulkan external memory apis. This is **not** just a
|
||||
/// suggestion. Check out vkExternalMemoryHandleTypeFlagBits in the Vulkan spec.
|
||||
///
|
||||
/// If you specify an handle type that doesnt make sense (for example, using a dma-buf handle type
|
||||
/// on Windows) when using this handle, a panic will happen.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(u32)]
|
||||
pub enum ExternalMemoryHandleType {
|
||||
OpaqueFd = ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD.as_raw(),
|
||||
OpaqueWin32 = ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32.as_raw(),
|
||||
OpaqueWin32Kmt = ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32_KMT.as_raw(),
|
||||
D3D11Texture = ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE.as_raw(),
|
||||
D3D11TextureKmt = ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT.as_raw(),
|
||||
D3D12Heap = ash::vk::ExternalMemoryHandleTypeFlags::D3D12_HEAP.as_raw(),
|
||||
D3D12Resource = ash::vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE.as_raw(),
|
||||
DmaBuf = ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT.as_raw(),
|
||||
AndroidHardwareBuffer =
|
||||
ash::vk::ExternalMemoryHandleTypeFlags::ANDROID_HARDWARE_BUFFER_ANDROID.as_raw(),
|
||||
HostAllocation = ash::vk::ExternalMemoryHandleTypeFlags::HOST_ALLOCATION_EXT.as_raw(),
|
||||
HostMappedForeignMemory =
|
||||
ash::vk::ExternalMemoryHandleTypeFlags::HOST_MAPPED_FOREIGN_MEMORY_EXT.as_raw(),
|
||||
vulkan_enum! {
|
||||
/// Describes a handle type used for Vulkan external memory apis. This is **not** just a
|
||||
/// suggestion. Check out vkExternalMemoryHandleTypeFlagBits in the Vulkan spec.
|
||||
///
|
||||
/// If you specify an handle type that doesnt make sense (for example, using a dma-buf handle type
|
||||
/// on Windows) when using this handle, a panic will happen.
|
||||
#[non_exhaustive]
|
||||
ExternalMemoryHandleType = ExternalMemoryHandleTypeFlags(u32);
|
||||
|
||||
// TODO: document
|
||||
OpaqueFd = OPAQUE_FD,
|
||||
|
||||
// TODO: document
|
||||
OpaqueWin32 = OPAQUE_WIN32,
|
||||
|
||||
// TODO: document
|
||||
OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
|
||||
|
||||
// TODO: document
|
||||
D3D11Texture = D3D11_TEXTURE,
|
||||
|
||||
// TODO: document
|
||||
D3D11TextureKmt = D3D11_TEXTURE_KMT,
|
||||
|
||||
// TODO: document
|
||||
D3D12Heap = D3D12_HEAP,
|
||||
|
||||
// TODO: document
|
||||
D3D12Resource = D3D12_RESOURCE,
|
||||
|
||||
// TODO: document
|
||||
DmaBuf = DMA_BUF_EXT {
|
||||
extensions: [ext_external_memory_dma_buf],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
AndroidHardwareBuffer = ANDROID_HARDWARE_BUFFER_ANDROID {
|
||||
extensions: [android_external_memory_android_hardware_buffer],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
HostAllocation = HOST_ALLOCATION_EXT {
|
||||
extensions: [ext_external_memory_host],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
HostMappedForeignMemory = HOST_MAPPED_FOREIGN_MEMORY_EXT {
|
||||
extensions: [ext_external_memory_host],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
ZirconVmo = ZIRCON_VMO_FUCHSIA {
|
||||
extensions: [fuchsia_external_memory],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
RdmaAddress = RDMA_ADDRESS_NV {
|
||||
extensions: [nv_external_memory_rdma],
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ExternalMemoryHandleType> for ash::vk::ExternalMemoryHandleTypeFlags {
|
||||
fn from(val: ExternalMemoryHandleType) -> Self {
|
||||
Self::from_raw(val as u32)
|
||||
}
|
||||
}
|
||||
vulkan_bitflags! {
|
||||
/// A mask of multiple handle types.
|
||||
#[non_exhaustive]
|
||||
ExternalMemoryHandleTypes = ExternalMemoryHandleTypeFlags(u32);
|
||||
|
||||
/// A mask of multiple handle types.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub struct ExternalMemoryHandleTypes {
|
||||
pub opaque_fd: bool,
|
||||
pub opaque_win32: bool,
|
||||
pub opaque_win32_kmt: bool,
|
||||
pub d3d11_texture: bool,
|
||||
pub d3d11_texture_kmt: bool,
|
||||
pub d3d12_heap: bool,
|
||||
pub d3d12_resource: bool,
|
||||
pub dma_buf: bool,
|
||||
pub android_hardware_buffer: bool,
|
||||
pub host_allocation: bool,
|
||||
pub host_mapped_foreign_memory: bool,
|
||||
// TODO: document
|
||||
opaque_fd = OPAQUE_FD,
|
||||
|
||||
// TODO: document
|
||||
opaque_win32 = OPAQUE_WIN32,
|
||||
|
||||
// TODO: document
|
||||
opaque_win32_kmt = OPAQUE_WIN32_KMT,
|
||||
|
||||
// TODO: document
|
||||
d3d11_texture = D3D11_TEXTURE,
|
||||
|
||||
// TODO: document
|
||||
d3d11_texture_kmt = D3D11_TEXTURE_KMT,
|
||||
|
||||
// TODO: document
|
||||
d3d12_heap = D3D12_HEAP,
|
||||
|
||||
// TODO: document
|
||||
d3d12_resource = D3D12_RESOURCE,
|
||||
|
||||
// TODO: document
|
||||
dma_buf = DMA_BUF_EXT {
|
||||
extensions: [ext_external_memory_dma_buf],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
android_hardware_buffer = ANDROID_HARDWARE_BUFFER_ANDROID {
|
||||
extensions: [android_external_memory_android_hardware_buffer],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
host_allocation = HOST_ALLOCATION_EXT {
|
||||
extensions: [ext_external_memory_host],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
host_mapped_foreign_memory = HOST_MAPPED_FOREIGN_MEMORY_EXT {
|
||||
extensions: [ext_external_memory_host],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
zircon_vmo = ZIRCON_VMO_FUCHSIA {
|
||||
extensions: [fuchsia_external_memory],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
rdma_address = RDMA_ADDRESS_NV {
|
||||
extensions: [nv_external_memory_rdma],
|
||||
},
|
||||
}
|
||||
|
||||
impl ExternalMemoryHandleTypes {
|
||||
/// Builds a `ExternalMemoryHandleTypes` with all values set to false. Useful as a default value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use vulkano::memory::ExternalMemoryHandleTypes as ExternalMemoryHandleTypes;
|
||||
///
|
||||
/// let _handle_type = ExternalMemoryHandleTypes {
|
||||
/// opaque_fd: true,
|
||||
/// .. ExternalMemoryHandleTypes::none()
|
||||
/// };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn none() -> Self {
|
||||
ExternalMemoryHandleTypes {
|
||||
opaque_fd: false,
|
||||
opaque_win32: false,
|
||||
opaque_win32_kmt: false,
|
||||
d3d11_texture: false,
|
||||
d3d11_texture_kmt: false,
|
||||
d3d12_heap: false,
|
||||
d3d12_resource: false,
|
||||
dma_buf: false,
|
||||
android_hardware_buffer: false,
|
||||
host_allocation: false,
|
||||
host_mapped_foreign_memory: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an `ExternalMemoryHandleTypes` for a posix file descriptor.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use vulkano::memory::ExternalMemoryHandleTypes as ExternalMemoryHandleTypes;
|
||||
///
|
||||
/// let _handle_type = ExternalMemoryHandleTypes::posix();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn posix() -> ExternalMemoryHandleTypes {
|
||||
ExternalMemoryHandleTypes {
|
||||
opaque_fd: true,
|
||||
..ExternalMemoryHandleTypes::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether any of the fields are set.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
let ExternalMemoryHandleTypes {
|
||||
opaque_fd,
|
||||
opaque_win32,
|
||||
opaque_win32_kmt,
|
||||
d3d11_texture,
|
||||
d3d11_texture_kmt,
|
||||
d3d12_heap,
|
||||
d3d12_resource,
|
||||
dma_buf,
|
||||
android_hardware_buffer,
|
||||
host_allocation,
|
||||
host_mapped_foreign_memory,
|
||||
} = *self;
|
||||
|
||||
!(opaque_fd
|
||||
|| opaque_win32
|
||||
|| opaque_win32_kmt
|
||||
|| d3d11_texture
|
||||
|| d3d11_texture_kmt
|
||||
|| d3d12_heap
|
||||
|| d3d12_resource
|
||||
|| dma_buf
|
||||
|| android_hardware_buffer
|
||||
|| host_allocation
|
||||
|| host_mapped_foreign_memory)
|
||||
}
|
||||
|
||||
/// Returns an iterator of `ExternalMemoryHandleType` enum values, representing the fields that
|
||||
/// are set in `self`.
|
||||
#[inline]
|
||||
@ -972,6 +989,9 @@ impl ExternalMemoryHandleTypes {
|
||||
android_hardware_buffer,
|
||||
host_allocation,
|
||||
host_mapped_foreign_memory,
|
||||
zircon_vmo,
|
||||
rdma_address,
|
||||
_ne: _,
|
||||
} = *self;
|
||||
|
||||
[
|
||||
@ -986,108 +1006,25 @@ impl ExternalMemoryHandleTypes {
|
||||
android_hardware_buffer.then(|| ExternalMemoryHandleType::AndroidHardwareBuffer),
|
||||
host_allocation.then(|| ExternalMemoryHandleType::HostAllocation),
|
||||
host_mapped_foreign_memory.then(|| ExternalMemoryHandleType::HostMappedForeignMemory),
|
||||
zircon_vmo.then(|| ExternalMemoryHandleType::HostMappedForeignMemory),
|
||||
rdma_address.then(|| ExternalMemoryHandleType::HostMappedForeignMemory),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalMemoryHandleTypes> for ash::vk::ExternalMemoryHandleTypeFlags {
|
||||
#[inline]
|
||||
fn from(val: ExternalMemoryHandleTypes) -> Self {
|
||||
let mut result = ash::vk::ExternalMemoryHandleTypeFlags::empty();
|
||||
if val.opaque_fd {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD;
|
||||
}
|
||||
if val.opaque_win32 {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32;
|
||||
}
|
||||
if val.opaque_win32_kmt {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32_KMT;
|
||||
}
|
||||
if val.d3d11_texture {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE;
|
||||
}
|
||||
if val.d3d11_texture_kmt {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT;
|
||||
}
|
||||
if val.d3d12_heap {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D12_HEAP;
|
||||
}
|
||||
if val.d3d12_resource {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE;
|
||||
}
|
||||
if val.dma_buf {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT;
|
||||
}
|
||||
if val.android_hardware_buffer {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::ANDROID_HARDWARE_BUFFER_ANDROID;
|
||||
}
|
||||
if val.host_allocation {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::HOST_ALLOCATION_EXT;
|
||||
}
|
||||
if val.host_mapped_foreign_memory {
|
||||
result |= ash::vk::ExternalMemoryHandleTypeFlags::HOST_MAPPED_FOREIGN_MEMORY_EXT
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ash::vk::ExternalMemoryHandleTypeFlags> for ExternalMemoryHandleTypes {
|
||||
fn from(val: ash::vk::ExternalMemoryHandleTypeFlags) -> Self {
|
||||
ExternalMemoryHandleTypes {
|
||||
opaque_fd: !(val & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD).is_empty(),
|
||||
opaque_win32: !(val & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32).is_empty(),
|
||||
opaque_win32_kmt: !(val & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32_KMT)
|
||||
.is_empty(),
|
||||
d3d11_texture: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE)
|
||||
.is_empty(),
|
||||
d3d11_texture_kmt: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT)
|
||||
.is_empty(),
|
||||
d3d12_heap: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D12_HEAP).is_empty(),
|
||||
d3d12_resource: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE)
|
||||
.is_empty(),
|
||||
dma_buf: !(val & ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT).is_empty(),
|
||||
android_hardware_buffer: !(val
|
||||
& ash::vk::ExternalMemoryHandleTypeFlags::ANDROID_HARDWARE_BUFFER_ANDROID)
|
||||
.is_empty(),
|
||||
host_allocation: !(val & ash::vk::ExternalMemoryHandleTypeFlags::HOST_ALLOCATION_EXT)
|
||||
.is_empty(),
|
||||
host_mapped_foreign_memory: !(val
|
||||
& ash::vk::ExternalMemoryHandleTypeFlags::HOST_MAPPED_FOREIGN_MEMORY_EXT)
|
||||
.is_empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for ExternalMemoryHandleTypes {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
ExternalMemoryHandleTypes {
|
||||
opaque_fd: self.opaque_fd || rhs.opaque_fd,
|
||||
opaque_win32: self.opaque_win32 || rhs.opaque_win32,
|
||||
opaque_win32_kmt: self.opaque_win32_kmt || rhs.opaque_win32_kmt,
|
||||
d3d11_texture: self.d3d11_texture || rhs.d3d11_texture,
|
||||
d3d11_texture_kmt: self.d3d11_texture_kmt || rhs.d3d11_texture_kmt,
|
||||
d3d12_heap: self.d3d12_heap || rhs.d3d12_heap,
|
||||
d3d12_resource: self.d3d12_resource || rhs.d3d12_resource,
|
||||
dma_buf: self.dma_buf || rhs.dma_buf,
|
||||
android_hardware_buffer: self.android_hardware_buffer || rhs.android_hardware_buffer,
|
||||
host_allocation: self.host_allocation || rhs.host_allocation,
|
||||
host_mapped_foreign_memory: self.host_mapped_foreign_memory
|
||||
|| rhs.host_mapped_foreign_memory,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type returned by functions related to `DeviceMemory`.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DeviceMemoryExportError {
|
||||
/// Not enough memory available.
|
||||
OomError(OomError),
|
||||
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
|
||||
/// The maximum number of allocations has been exceeded.
|
||||
TooManyObjects,
|
||||
|
||||
@ -1113,6 +1050,11 @@ impl fmt::Display for DeviceMemoryExportError {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
Self::OomError(_) => write!(fmt, "not enough memory available"),
|
||||
Self::ExtensionNotEnabled { extension, reason } => write!(
|
||||
fmt,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
),
|
||||
Self::TooManyObjects => {
|
||||
write!(fmt, "the maximum number of allocations has been exceeded")
|
||||
}
|
||||
@ -1147,6 +1089,16 @@ impl From<OomError> for DeviceMemoryExportError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for DeviceMemoryExportError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents device memory that has been mapped in a CPU-accessible space.
|
||||
///
|
||||
/// In order to access the contents of the allocated memory, you can use the `read` and `write`
|
||||
|
@ -91,7 +91,7 @@ where
|
||||
memory_type_index: memory_type.id(),
|
||||
export_handle_types: ExternalMemoryHandleTypes {
|
||||
opaque_fd: true,
|
||||
..ExternalMemoryHandleTypes::none()
|
||||
..ExternalMemoryHandleTypes::empty()
|
||||
},
|
||||
..MemoryAllocateInfo::dedicated_allocation(dedicated_allocation)
|
||||
},
|
||||
|
@ -486,8 +486,16 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let data_buffer =
|
||||
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
|
||||
let data_buffer = CpuAccessibleBuffer::from_data(
|
||||
device.clone(),
|
||||
BufferUsage {
|
||||
storage_buffer: true,
|
||||
..BufferUsage::empty()
|
||||
},
|
||||
false,
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let set = PersistentDescriptorSet::new(
|
||||
pipeline.layout().set_layouts().get(0).unwrap().clone(),
|
||||
|
@ -15,7 +15,7 @@ use super::{
|
||||
color_blend::{
|
||||
AttachmentBlend, ColorBlendAttachmentState, ColorBlendState, ColorComponents, LogicOp,
|
||||
},
|
||||
depth_stencil::DepthStencilState,
|
||||
depth_stencil::{DepthStencilState, StencilOps},
|
||||
discard_rectangle::DiscardRectangleState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology, PrimitiveTopologyClass},
|
||||
multisample::MultisampleState,
|
||||
@ -719,34 +719,42 @@ where
|
||||
} = input_assembly_state;
|
||||
|
||||
match topology {
|
||||
PartialStateMode::Fixed(topology) => match topology {
|
||||
PrimitiveTopology::LineListWithAdjacency
|
||||
| PrimitiveTopology::LineStripWithAdjacency
|
||||
| PrimitiveTopology::TriangleListWithAdjacency
|
||||
| PrimitiveTopology::TriangleStripWithAdjacency => {
|
||||
// VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429
|
||||
if !device.enabled_features().geometry_shader {
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "geometry_shader",
|
||||
reason: "InputAssemblyState::topology was set to a WithAdjacency PrimitiveTopology",
|
||||
});
|
||||
}
|
||||
}
|
||||
PrimitiveTopology::PatchList => {
|
||||
// VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430
|
||||
if !device.enabled_features().tessellation_shader {
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "tessellation_shader",
|
||||
reason: "InputAssemblyState::topology was set to PrimitiveTopology::PatchList",
|
||||
});
|
||||
}
|
||||
PartialStateMode::Fixed(topology) => {
|
||||
// VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter
|
||||
topology.validate(device)?;
|
||||
|
||||
// TODO:
|
||||
// VUID-VkGraphicsPipelineCreateInfo-topology-00737
|
||||
match topology {
|
||||
PrimitiveTopology::LineListWithAdjacency
|
||||
| PrimitiveTopology::LineStripWithAdjacency
|
||||
| PrimitiveTopology::TriangleListWithAdjacency
|
||||
| PrimitiveTopology::TriangleStripWithAdjacency => {
|
||||
// VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429
|
||||
if !device.enabled_features().geometry_shader {
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "geometry_shader",
|
||||
reason: "InputAssemblyState::topology was set to a WithAdjacency PrimitiveTopology",
|
||||
});
|
||||
}
|
||||
}
|
||||
PrimitiveTopology::PatchList => {
|
||||
// VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430
|
||||
if !device.enabled_features().tessellation_shader {
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "tessellation_shader",
|
||||
reason: "InputAssemblyState::topology was set to PrimitiveTopology::PatchList",
|
||||
});
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// VUID-VkGraphicsPipelineCreateInfo-topology-00737
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
PartialStateMode::Dynamic(_topology_class) => {
|
||||
}
|
||||
PartialStateMode::Dynamic(topology_class) => {
|
||||
// VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter
|
||||
topology_class.example().validate(device)?;
|
||||
|
||||
// VUID?
|
||||
if !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
@ -1055,6 +1063,9 @@ where
|
||||
line_stipple,
|
||||
} = rasterization_state;
|
||||
|
||||
// VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-parameter
|
||||
polygon_mode.validate(device)?;
|
||||
|
||||
// VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782
|
||||
if depth_clamp_enable && !device.enabled_features().depth_clamp {
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
@ -1084,26 +1095,40 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
// VUID?
|
||||
if matches!(cull_mode, StateMode::Dynamic)
|
||||
&& !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state",
|
||||
reason: "RasterizationState::cull_mode was set to Dynamic",
|
||||
});
|
||||
match cull_mode {
|
||||
StateMode::Fixed(cull_mode) => {
|
||||
// VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter
|
||||
cull_mode.validate(device)?;
|
||||
}
|
||||
StateMode::Dynamic => {
|
||||
// VUID?
|
||||
if !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state",
|
||||
reason: "RasterizationState::cull_mode was set to Dynamic",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VUID?
|
||||
if matches!(front_face, StateMode::Dynamic)
|
||||
&& !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state",
|
||||
reason: "RasterizationState::front_face was set to Dynamic",
|
||||
});
|
||||
match front_face {
|
||||
StateMode::Fixed(front_face) => {
|
||||
// VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter
|
||||
front_face.validate(device)?;
|
||||
}
|
||||
StateMode::Dynamic => {
|
||||
// VUID?
|
||||
if !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state",
|
||||
reason: "RasterizationState::front_face was set to Dynamic",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(depth_bias_state) = depth_bias {
|
||||
@ -1142,6 +1167,9 @@ where
|
||||
}
|
||||
|
||||
if device.enabled_extensions().ext_line_rasterization {
|
||||
// VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-parameter
|
||||
line_rasterization_mode.validate(device)?;
|
||||
|
||||
match line_rasterization_mode {
|
||||
LineRasterizationMode::Default => (),
|
||||
LineRasterizationMode::Rectangular => {
|
||||
@ -1248,11 +1276,14 @@ where
|
||||
// Discard rectangle state
|
||||
{
|
||||
let &DiscardRectangleState {
|
||||
mode: _,
|
||||
mode,
|
||||
ref rectangles,
|
||||
} = discard_rectangle_state;
|
||||
|
||||
if device.enabled_extensions().ext_discard_rectangles {
|
||||
// VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleMode-parameter
|
||||
mode.validate(device)?;
|
||||
|
||||
let discard_rectangle_count = match *rectangles {
|
||||
PartialStateMode::Dynamic(count) => count,
|
||||
PartialStateMode::Fixed(ref rectangles) => rectangles.len() as u32,
|
||||
@ -1642,15 +1673,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// VUID?
|
||||
if matches!(compare_op, StateMode::Dynamic)
|
||||
&& !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state",
|
||||
reason: "DepthState::compare_op was set to Dynamic",
|
||||
});
|
||||
match compare_op {
|
||||
StateMode::Fixed(compare_op) => {
|
||||
// VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter
|
||||
compare_op.validate(device)?;
|
||||
}
|
||||
StateMode::Dynamic => {
|
||||
// VUID?
|
||||
if !(device.api_version() >= Version::V1_3
|
||||
|| device.enabled_features().extended_dynamic_state)
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state",
|
||||
reason: "DepthState::compare_op was set to Dynamic",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1723,7 +1761,28 @@ where
|
||||
}
|
||||
|
||||
match (front.ops, back.ops) {
|
||||
(StateMode::Fixed(_), StateMode::Fixed(_)) => (),
|
||||
(StateMode::Fixed(front_ops), StateMode::Fixed(back_ops)) => {
|
||||
for ops in [front_ops, back_ops] {
|
||||
let StencilOps {
|
||||
fail_op,
|
||||
pass_op,
|
||||
depth_fail_op,
|
||||
compare_op,
|
||||
} = ops;
|
||||
|
||||
// VUID-VkStencilOpState-failOp-parameter
|
||||
fail_op.validate(device)?;
|
||||
|
||||
// VUID-VkStencilOpState-passOp-parameter
|
||||
pass_op.validate(device)?;
|
||||
|
||||
// VUID-VkStencilOpState-depthFailOp-parameter
|
||||
depth_fail_op.validate(device)?;
|
||||
|
||||
// VUID-VkStencilOpState-compareOp-parameter
|
||||
compare_op.validate(device)?;
|
||||
}
|
||||
}
|
||||
(StateMode::Dynamic, StateMode::Dynamic) => {
|
||||
// VUID?
|
||||
if !(device.api_version() >= Version::V1_3
|
||||
@ -1783,6 +1842,9 @@ where
|
||||
alpha_to_one_enable,
|
||||
} = multisample_state;
|
||||
|
||||
// VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter
|
||||
rasterization_samples.validate(device)?;
|
||||
|
||||
match render_pass {
|
||||
PipelineRenderPassType::BeginRenderPass(subpass) => {
|
||||
if let Some(samples) = subpass.num_samples() {
|
||||
@ -1850,14 +1912,20 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
// VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869
|
||||
if matches!(logic_op, StateMode::Dynamic)
|
||||
&& !device.enabled_features().extended_dynamic_state2_logic_op
|
||||
{
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state2_logic_op",
|
||||
reason: "ColorBlendState::logic_op was set to Some(Dynamic)",
|
||||
});
|
||||
match logic_op {
|
||||
StateMode::Fixed(logic_op) => {
|
||||
// VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607
|
||||
logic_op.validate(device)?
|
||||
}
|
||||
StateMode::Dynamic => {
|
||||
// VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869
|
||||
if !device.enabled_features().extended_dynamic_state2_logic_op {
|
||||
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
|
||||
feature: "extended_dynamic_state2_logic_op",
|
||||
reason: "ColorBlendState::logic_op was set to Some(Dynamic)",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1903,13 +1971,40 @@ where
|
||||
} = state;
|
||||
|
||||
if let Some(blend) = blend {
|
||||
let AttachmentBlend {
|
||||
color_op,
|
||||
color_source,
|
||||
color_destination,
|
||||
alpha_op,
|
||||
alpha_source,
|
||||
alpha_destination,
|
||||
} = blend;
|
||||
|
||||
// VUID-VkPipelineColorBlendAttachmentState-colorBlendOp-parameter
|
||||
color_op.validate(device)?;
|
||||
|
||||
// VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-parameter
|
||||
color_source.validate(device)?;
|
||||
|
||||
// VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-parameter
|
||||
color_destination.validate(device)?;
|
||||
|
||||
// VUID-VkPipelineColorBlendAttachmentState-alphaBlendOp-parameter
|
||||
alpha_op.validate(device)?;
|
||||
|
||||
// VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-parameter
|
||||
alpha_source.validate(device)?;
|
||||
|
||||
// VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-parameter
|
||||
alpha_destination.validate(device)?;
|
||||
|
||||
// VUID?
|
||||
if !device.enabled_features().dual_src_blend
|
||||
&& [
|
||||
blend.color_source,
|
||||
blend.color_destination,
|
||||
blend.alpha_source,
|
||||
blend.alpha_destination,
|
||||
color_source,
|
||||
color_destination,
|
||||
alpha_source,
|
||||
alpha_destination,
|
||||
]
|
||||
.into_iter()
|
||||
.any(|blend_factor| {
|
||||
|
@ -21,7 +21,10 @@
|
||||
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
|
||||
//! will take precedence if it is activated, otherwise the blending operation is applied.
|
||||
|
||||
use crate::pipeline::StateMode;
|
||||
use crate::{
|
||||
macros::{vulkan_bitflags, vulkan_enum},
|
||||
pipeline::StateMode,
|
||||
};
|
||||
|
||||
/// Describes how the color output of the fragment shader is written to the attachment. See the
|
||||
/// documentation of the `blend` module for more info.
|
||||
@ -140,55 +143,65 @@ impl Default for ColorBlendState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Which logical operation to apply to the output values.
|
||||
///
|
||||
/// The operation is applied individually for each channel (red, green, blue and alpha).
|
||||
///
|
||||
/// Only relevant for integer or unsigned attachments.
|
||||
///
|
||||
/// Also note that some implementations don't support logic operations.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum LogicOp {
|
||||
/// Returns `0`.
|
||||
Clear = ash::vk::LogicOp::CLEAR.as_raw(),
|
||||
/// Returns `source & destination`.
|
||||
And = ash::vk::LogicOp::AND.as_raw(),
|
||||
/// Returns `source & !destination`.
|
||||
AndReverse = ash::vk::LogicOp::AND_REVERSE.as_raw(),
|
||||
/// Returns `source`.
|
||||
Copy = ash::vk::LogicOp::COPY.as_raw(),
|
||||
/// Returns `!source & destination`.
|
||||
AndInverted = ash::vk::LogicOp::AND_INVERTED.as_raw(),
|
||||
/// Returns `destination`.
|
||||
Noop = ash::vk::LogicOp::NO_OP.as_raw(),
|
||||
/// Returns `source ^ destination`.
|
||||
Xor = ash::vk::LogicOp::XOR.as_raw(),
|
||||
/// Returns `source | destination`.
|
||||
Or = ash::vk::LogicOp::OR.as_raw(),
|
||||
/// Returns `!(source | destination)`.
|
||||
Nor = ash::vk::LogicOp::NOR.as_raw(),
|
||||
/// Returns `!(source ^ destination)`.
|
||||
Equivalent = ash::vk::LogicOp::EQUIVALENT.as_raw(),
|
||||
/// Returns `!destination`.
|
||||
Invert = ash::vk::LogicOp::INVERT.as_raw(),
|
||||
/// Returns `source | !destination.
|
||||
OrReverse = ash::vk::LogicOp::OR_REVERSE.as_raw(),
|
||||
/// Returns `!source`.
|
||||
CopyInverted = ash::vk::LogicOp::COPY_INVERTED.as_raw(),
|
||||
/// Returns `!source | destination`.
|
||||
OrInverted = ash::vk::LogicOp::OR_INVERTED.as_raw(),
|
||||
/// Returns `!(source & destination)`.
|
||||
Nand = ash::vk::LogicOp::NAND.as_raw(),
|
||||
/// Returns `!0` (all bits set to 1).
|
||||
Set = ash::vk::LogicOp::SET.as_raw(),
|
||||
}
|
||||
vulkan_enum! {
|
||||
/// Which logical operation to apply to the output values.
|
||||
///
|
||||
/// The operation is applied individually for each channel (red, green, blue and alpha).
|
||||
///
|
||||
/// Only relevant for integer or unsigned attachments.
|
||||
///
|
||||
/// Also note that some implementations don't support logic operations.
|
||||
#[non_exhaustive]
|
||||
LogicOp = LogicOp(i32);
|
||||
|
||||
/// Returns `0`.
|
||||
Clear = CLEAR,
|
||||
|
||||
/// Returns `source & destination`.
|
||||
And = AND,
|
||||
|
||||
/// Returns `source & !destination`.
|
||||
AndReverse = AND_REVERSE,
|
||||
|
||||
/// Returns `source`.
|
||||
Copy = COPY,
|
||||
|
||||
/// Returns `!source & destination`.
|
||||
AndInverted = AND_INVERTED,
|
||||
|
||||
/// Returns `destination`.
|
||||
Noop = NO_OP,
|
||||
|
||||
/// Returns `source ^ destination`.
|
||||
Xor = XOR,
|
||||
|
||||
/// Returns `source | destination`.
|
||||
Or = OR,
|
||||
|
||||
/// Returns `!(source | destination)`.
|
||||
Nor = NOR,
|
||||
|
||||
/// Returns `!(source ^ destination)`.
|
||||
Equivalent = EQUIVALENT,
|
||||
|
||||
/// Returns `!destination`.
|
||||
Invert = INVERT,
|
||||
|
||||
/// Returns `source | !destination.
|
||||
OrReverse = OR_REVERSE,
|
||||
|
||||
/// Returns `!source`.
|
||||
CopyInverted = COPY_INVERTED,
|
||||
|
||||
/// Returns `!source | destination`.
|
||||
OrInverted = OR_INVERTED,
|
||||
|
||||
/// Returns `!(source & destination)`.
|
||||
Nand = NAND,
|
||||
|
||||
/// Returns `!0` (all bits set to 1).
|
||||
Set = SET,
|
||||
|
||||
impl From<LogicOp> for ash::vk::LogicOp {
|
||||
#[inline]
|
||||
fn from(val: LogicOp) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LogicOp {
|
||||
@ -304,162 +317,343 @@ impl From<AttachmentBlend> for ash::vk::PipelineColorBlendAttachmentState {
|
||||
}
|
||||
}
|
||||
|
||||
/// The operation that takes `source` (output from the fragment shader), `destination` (value
|
||||
/// currently in the framebuffer attachment) and `blend_constant` input values,
|
||||
/// and produces new inputs to be fed to `BlendOp`.
|
||||
///
|
||||
/// Some operations take `source1` as an input, representing the second source value. The
|
||||
/// [`dual_src_blend`](crate::device::Features::dual_src_blend) feature must be enabled on the
|
||||
/// device when these are used.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum BlendFactor {
|
||||
vulkan_enum! {
|
||||
/// The operation that takes `source` (output from the fragment shader), `destination` (value
|
||||
/// currently in the framebuffer attachment) and `blend_constant` input values,
|
||||
/// and produces new inputs to be fed to `BlendOp`.
|
||||
///
|
||||
/// Some operations take `source1` as an input, representing the second source value. The
|
||||
/// [`dual_src_blend`](crate::device::Features::dual_src_blend) feature must be enabled on the
|
||||
/// device when these are used.
|
||||
#[non_exhaustive]
|
||||
BlendFactor = BlendFactor(i32);
|
||||
|
||||
/// Always `0`.
|
||||
Zero = ash::vk::BlendFactor::ZERO.as_raw(),
|
||||
Zero = ZERO,
|
||||
|
||||
/// Always `1`.
|
||||
One = ash::vk::BlendFactor::ONE.as_raw(),
|
||||
One = ONE,
|
||||
|
||||
/// `source` component-wise.
|
||||
SrcColor = ash::vk::BlendFactor::SRC_COLOR.as_raw(),
|
||||
SrcColor = SRC_COLOR,
|
||||
|
||||
/// `1 - source` component-wise.
|
||||
OneMinusSrcColor = ash::vk::BlendFactor::ONE_MINUS_SRC_COLOR.as_raw(),
|
||||
OneMinusSrcColor = ONE_MINUS_SRC_COLOR,
|
||||
|
||||
/// `destination` component-wise.
|
||||
DstColor = ash::vk::BlendFactor::DST_COLOR.as_raw(),
|
||||
DstColor = DST_COLOR,
|
||||
|
||||
/// `1 - destination` component-wise.
|
||||
OneMinusDstColor = ash::vk::BlendFactor::ONE_MINUS_DST_COLOR.as_raw(),
|
||||
OneMinusDstColor = ONE_MINUS_DST_COLOR,
|
||||
|
||||
/// `source.a` for all components.
|
||||
SrcAlpha = ash::vk::BlendFactor::SRC_ALPHA.as_raw(),
|
||||
SrcAlpha = SRC_ALPHA,
|
||||
|
||||
/// `1 - source.a` for all components.
|
||||
OneMinusSrcAlpha = ash::vk::BlendFactor::ONE_MINUS_SRC_ALPHA.as_raw(),
|
||||
OneMinusSrcAlpha = ONE_MINUS_SRC_ALPHA,
|
||||
|
||||
/// `destination.a` for all components.
|
||||
DstAlpha = ash::vk::BlendFactor::DST_ALPHA.as_raw(),
|
||||
DstAlpha = DST_ALPHA,
|
||||
|
||||
/// `1 - destination.a` for all components.
|
||||
OneMinusDstAlpha = ash::vk::BlendFactor::ONE_MINUS_DST_ALPHA.as_raw(),
|
||||
OneMinusDstAlpha = ONE_MINUS_DST_ALPHA,
|
||||
|
||||
/// `blend_constants` component-wise.
|
||||
ConstantColor = ash::vk::BlendFactor::CONSTANT_COLOR.as_raw(),
|
||||
ConstantColor = CONSTANT_COLOR,
|
||||
|
||||
/// `1 - blend_constants` component-wise.
|
||||
OneMinusConstantColor = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR.as_raw(),
|
||||
OneMinusConstantColor = ONE_MINUS_CONSTANT_COLOR,
|
||||
|
||||
/// `blend_constants.a` for all components.
|
||||
ConstantAlpha = ash::vk::BlendFactor::CONSTANT_ALPHA.as_raw(),
|
||||
ConstantAlpha = CONSTANT_ALPHA,
|
||||
|
||||
/// `1 - blend_constants.a` for all components.
|
||||
OneMinusConstantAlpha = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_ALPHA.as_raw(),
|
||||
OneMinusConstantAlpha = ONE_MINUS_CONSTANT_ALPHA,
|
||||
|
||||
/// For the alpha component, always `1`. For the color components,
|
||||
/// `min(source.a, 1 - destination.a)` for all components.
|
||||
SrcAlphaSaturate = ash::vk::BlendFactor::SRC_ALPHA_SATURATE.as_raw(),
|
||||
SrcAlphaSaturate = SRC_ALPHA_SATURATE,
|
||||
|
||||
/// `source1` component-wise.
|
||||
Src1Color = ash::vk::BlendFactor::SRC1_COLOR.as_raw(),
|
||||
Src1Color = SRC1_COLOR,
|
||||
|
||||
/// `1 - source1` component-wise.
|
||||
OneMinusSrc1Color = ash::vk::BlendFactor::ONE_MINUS_SRC1_COLOR.as_raw(),
|
||||
OneMinusSrc1Color = ONE_MINUS_SRC1_COLOR,
|
||||
|
||||
/// `source1.a` for all components.
|
||||
Src1Alpha = ash::vk::BlendFactor::SRC1_ALPHA.as_raw(),
|
||||
Src1Alpha = SRC1_ALPHA,
|
||||
|
||||
/// `1 - source1.a` for all components.
|
||||
OneMinusSrc1Alpha = ash::vk::BlendFactor::ONE_MINUS_SRC1_ALPHA.as_raw(),
|
||||
OneMinusSrc1Alpha = ONE_MINUS_SRC1_ALPHA,
|
||||
}
|
||||
|
||||
impl From<BlendFactor> for ash::vk::BlendFactor {
|
||||
#[inline]
|
||||
fn from(val: BlendFactor) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
vulkan_enum! {
|
||||
/// The arithmetic operation that is applied between the `source` and `destination` component
|
||||
/// values, after the appropriate `BlendFactor` is applied to both.
|
||||
#[non_exhaustive]
|
||||
BlendOp = BlendOp(i32);
|
||||
|
||||
/// The arithmetic operation that is applied between the `source` and `destination` component
|
||||
/// values, after the appropriate `BlendFactor` is applied to both.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum BlendOp {
|
||||
/// `source + destination`.
|
||||
Add = ash::vk::BlendOp::ADD.as_raw(),
|
||||
Add = ADD,
|
||||
|
||||
/// `source - destination`.
|
||||
Subtract = ash::vk::BlendOp::SUBTRACT.as_raw(),
|
||||
Subtract = SUBTRACT,
|
||||
|
||||
/// `destination - source`.
|
||||
ReverseSubtract = ash::vk::BlendOp::REVERSE_SUBTRACT.as_raw(),
|
||||
ReverseSubtract = REVERSE_SUBTRACT,
|
||||
|
||||
/// `min(source, destination)`.
|
||||
Min = ash::vk::BlendOp::MIN.as_raw(),
|
||||
Min = MIN,
|
||||
|
||||
/// `max(source, destination)`.
|
||||
Max = ash::vk::BlendOp::MAX.as_raw(),
|
||||
Max = MAX,
|
||||
|
||||
/*
|
||||
// TODO: document
|
||||
Zero = ZERO_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Src = SRC_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Dst = DST_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
SrcOver = SRC_OVER_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DstOver = DST_OVER_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
SrcIn = SRC_IN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DstIn = DST_IN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
SrcOut = SRC_OUT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DstOut = DST_OUT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
SrcAtop = SRC_ATOP_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
DstAtop = DST_ATOP_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Xor = XOR_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Multiply = MULTIPLY_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Screen = SCREEN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Overlay = OVERLAY_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Darken = DARKEN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Lighten = LIGHTEN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Colordodge = COLORDODGE_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Colorburn = COLORBURN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Hardlight = HARDLIGHT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Softlight = SOFTLIGHT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Difference = DIFFERENCE_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Exclusion = EXCLUSION_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Invert = INVERT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
InvertRgb = INVERT_RGB_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Lineardodge = LINEARDODGE_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Linearburn = LINEARBURN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Vividlight = VIVIDLIGHT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Linearlight = LINEARLIGHT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Pinlight = PINLIGHT_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Hardmix = HARDMIX_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
HslHue = HSL_HUE_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
HslSaturation = HSL_SATURATION_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
HslColor = HSL_COLOR_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
HslLuminosity = HSL_LUMINOSITY_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Plus = PLUS_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
PlusClamped = PLUS_CLAMPED_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
PlusClampedAlpha = PLUS_CLAMPED_ALPHA_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
PlusDarker = PLUS_DARKER_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Minus = MINUS_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
MinusClamped = MINUS_CLAMPED_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Contrast = CONTRAST_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
InvertOvg = INVERT_OVG_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Red = RED_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Green = GREEN_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
|
||||
// TODO: document
|
||||
Blue = BLUE_EXT {
|
||||
extensions: [ext_blend_operation_advanced],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
impl From<BlendOp> for ash::vk::BlendOp {
|
||||
#[inline]
|
||||
fn from(val: BlendOp) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
vulkan_bitflags! {
|
||||
/// A mask specifying color components that can be written to a framebuffer attachment.
|
||||
ColorComponents = ColorComponentFlags(u32);
|
||||
|
||||
/// A mask specifying color components that can be written to a framebuffer attachment.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct ColorComponents {
|
||||
#[allow(missing_docs)]
|
||||
pub r: bool,
|
||||
#[allow(missing_docs)]
|
||||
pub g: bool,
|
||||
#[allow(missing_docs)]
|
||||
pub b: bool,
|
||||
#[allow(missing_docs)]
|
||||
pub a: bool,
|
||||
}
|
||||
/// The red component.
|
||||
r = R,
|
||||
|
||||
impl ColorComponents {
|
||||
/// Returns a mask that specifies no components.
|
||||
#[inline]
|
||||
pub fn none() -> Self {
|
||||
Self {
|
||||
r: false,
|
||||
g: false,
|
||||
b: false,
|
||||
a: false,
|
||||
}
|
||||
}
|
||||
/// The green component.
|
||||
g = G,
|
||||
|
||||
/// Returns a mask that specifies all components.
|
||||
#[inline]
|
||||
pub fn all() -> Self {
|
||||
Self {
|
||||
r: true,
|
||||
g: true,
|
||||
b: true,
|
||||
a: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// The blue component.
|
||||
b = B,
|
||||
|
||||
impl From<ColorComponents> for ash::vk::ColorComponentFlags {
|
||||
fn from(val: ColorComponents) -> Self {
|
||||
let mut result = Self::empty();
|
||||
if val.r {
|
||||
result |= ash::vk::ColorComponentFlags::R;
|
||||
}
|
||||
if val.g {
|
||||
result |= ash::vk::ColorComponentFlags::G;
|
||||
}
|
||||
if val.b {
|
||||
result |= ash::vk::ColorComponentFlags::B;
|
||||
}
|
||||
if val.a {
|
||||
result |= ash::vk::ColorComponentFlags::A;
|
||||
}
|
||||
result
|
||||
}
|
||||
/// The alpha component.
|
||||
a = A,
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use super::vertex_input::IncompatibleVertexDefinitionError;
|
||||
use crate::{
|
||||
descriptor_set::layout::DescriptorSetLayoutCreationError,
|
||||
format::{Format, NumericType},
|
||||
macros::ExtensionNotEnabled,
|
||||
pipeline::layout::{PipelineLayoutCreationError, PipelineLayoutSupersetError},
|
||||
shader::ShaderInterfaceMismatchError,
|
||||
OomError, VulkanError,
|
||||
@ -434,3 +435,13 @@ impl From<VulkanError> for GraphicsPipelineCreationError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExtensionNotEnabled> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: ExtensionNotEnabled) -> Self {
|
||||
Self::ExtensionNotEnabled {
|
||||
extension: err.extension,
|
||||
reason: err.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
//! value in the stencil buffer at each fragment's location. Depending on the outcome of the
|
||||
//! depth and stencil tests, the value of the stencil buffer at that location can be updated.
|
||||
|
||||
use crate::pipeline::StateMode;
|
||||
use crate::{macros::vulkan_enum, pipeline::StateMode};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
/// The state in a graphics pipeline describing how the depth, depth bounds and stencil tests
|
||||
@ -244,41 +244,49 @@ impl Default for StencilOps {
|
||||
}
|
||||
}
|
||||
|
||||
/// Operation to perform after the depth and stencil tests.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum StencilOp {
|
||||
Keep = ash::vk::StencilOp::KEEP.as_raw(),
|
||||
Zero = ash::vk::StencilOp::ZERO.as_raw(),
|
||||
Replace = ash::vk::StencilOp::REPLACE.as_raw(),
|
||||
IncrementAndClamp = ash::vk::StencilOp::INCREMENT_AND_CLAMP.as_raw(),
|
||||
DecrementAndClamp = ash::vk::StencilOp::DECREMENT_AND_CLAMP.as_raw(),
|
||||
Invert = ash::vk::StencilOp::INVERT.as_raw(),
|
||||
IncrementAndWrap = ash::vk::StencilOp::INCREMENT_AND_WRAP.as_raw(),
|
||||
DecrementAndWrap = ash::vk::StencilOp::DECREMENT_AND_WRAP.as_raw(),
|
||||
vulkan_enum! {
|
||||
/// Operation to perform after the depth and stencil tests.
|
||||
#[non_exhaustive]
|
||||
StencilOp = StencilOp(i32);
|
||||
|
||||
// TODO: document
|
||||
Keep = KEEP,
|
||||
|
||||
// TODO: document
|
||||
Zero = ZERO,
|
||||
|
||||
// TODO: document
|
||||
Replace = REPLACE,
|
||||
|
||||
// TODO: document
|
||||
IncrementAndClamp = INCREMENT_AND_CLAMP,
|
||||
|
||||
// TODO: document
|
||||
DecrementAndClamp = DECREMENT_AND_CLAMP,
|
||||
|
||||
// TODO: document
|
||||
Invert = INVERT,
|
||||
|
||||
// TODO: document
|
||||
IncrementAndWrap = INCREMENT_AND_WRAP,
|
||||
|
||||
// TODO: document
|
||||
DecrementAndWrap = DECREMENT_AND_WRAP,
|
||||
}
|
||||
|
||||
impl From<StencilOp> for ash::vk::StencilOp {
|
||||
#[inline]
|
||||
fn from(val: StencilOp) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
}
|
||||
vulkan_enum! {
|
||||
/// Specifies a face for stencil operations.
|
||||
#[non_exhaustive]
|
||||
StencilFaces = StencilFaceFlags(u32);
|
||||
|
||||
/// Specifies a face for stencil operations.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
pub enum StencilFaces {
|
||||
Front = ash::vk::StencilFaceFlags::FRONT.as_raw(),
|
||||
Back = ash::vk::StencilFaceFlags::BACK.as_raw(),
|
||||
FrontAndBack = ash::vk::StencilFaceFlags::FRONT_AND_BACK.as_raw(),
|
||||
}
|
||||
// TODO: document
|
||||
Front = FRONT,
|
||||
|
||||
impl From<StencilFaces> for ash::vk::StencilFaceFlags {
|
||||
#[inline]
|
||||
fn from(val: StencilFaces) -> Self {
|
||||
Self::from_raw(val as u32)
|
||||
}
|
||||
// TODO: document
|
||||
Back = BACK,
|
||||
|
||||
// TODO: document
|
||||
FrontAndBack = FRONT_AND_BACK,
|
||||
}
|
||||
|
||||
/// Specifies a dynamic state value for the front and back faces.
|
||||
@ -288,33 +296,34 @@ pub struct DynamicStencilValue {
|
||||
pub back: u32,
|
||||
}
|
||||
|
||||
/// Specifies how two values should be compared to decide whether a test passes or fails.
|
||||
///
|
||||
/// Used for both depth testing and stencil testing.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum CompareOp {
|
||||
/// The test never passes.
|
||||
Never = ash::vk::CompareOp::NEVER.as_raw(),
|
||||
/// The test passes if `value < reference_value`.
|
||||
Less = ash::vk::CompareOp::LESS.as_raw(),
|
||||
/// The test passes if `value == reference_value`.
|
||||
Equal = ash::vk::CompareOp::EQUAL.as_raw(),
|
||||
/// The test passes if `value <= reference_value`.
|
||||
LessOrEqual = ash::vk::CompareOp::LESS_OR_EQUAL.as_raw(),
|
||||
/// The test passes if `value > reference_value`.
|
||||
Greater = ash::vk::CompareOp::GREATER.as_raw(),
|
||||
/// The test passes if `value != reference_value`.
|
||||
NotEqual = ash::vk::CompareOp::NOT_EQUAL.as_raw(),
|
||||
/// The test passes if `value >= reference_value`.
|
||||
GreaterOrEqual = ash::vk::CompareOp::GREATER_OR_EQUAL.as_raw(),
|
||||
/// The test always passes.
|
||||
Always = ash::vk::CompareOp::ALWAYS.as_raw(),
|
||||
}
|
||||
vulkan_enum! {
|
||||
/// Specifies how two values should be compared to decide whether a test passes or fails.
|
||||
///
|
||||
/// Used for both depth testing and stencil testing.
|
||||
#[non_exhaustive]
|
||||
CompareOp = CompareOp(i32);
|
||||
|
||||
impl From<CompareOp> for ash::vk::CompareOp {
|
||||
#[inline]
|
||||
fn from(val: CompareOp) -> Self {
|
||||
Self::from_raw(val as i32)
|
||||
}
|
||||
/// The test never passes.
|
||||
Never = NEVER,
|
||||
|
||||
/// The test passes if `value < reference_value`.
|
||||
Less = LESS,
|
||||
|
||||
/// The test passes if `value == reference_value`.
|
||||
Equal = EQUAL,
|
||||
|
||||
/// The test passes if `value <= reference_value`.
|
||||
LessOrEqual = LESS_OR_EQUAL,
|
||||
|
||||
/// The test passes if `value > reference_value`.
|
||||
Greater = GREATER,
|
||||
|
||||
/// The test passes if `value != reference_value`.
|
||||
NotEqual = NOT_EQUAL,
|
||||
|
||||
/// The test passes if `value >= reference_value`.
|
||||
GreaterOrEqual = GREATER_OR_EQUAL,
|
||||
|
||||
/// The test always passes.
|
||||
Always = ALWAYS,
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user