Macrofy all Vulkan bitflag and enum types, check for device support (#1964)

This commit is contained in:
Rua 2022-09-05 22:16:40 +02:00 committed by GitHub
parent f96768f556
commit 2705984c77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 5848 additions and 4504 deletions

View File

@ -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,

View File

@ -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()

View File

@ -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()

View File

@ -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");

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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(),
)

View File

@ -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()

View File

@ -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,
)

View File

@ -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),
)

View File

@ -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),
)

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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,
)

View File

@ -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(),

View File

@ -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! {

View File

@ -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(),
)

View File

@ -62,7 +62,7 @@ fn main() {
storage: true,
color_attachment: true,
transfer_dst: true,
..ImageUsage::none()
..ImageUsage::empty()
},
);

View File

@ -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,
)

View File

@ -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),
)

View File

@ -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()
},

View File

@ -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();

View File

@ -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(),
)

View File

@ -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),
)

View File

@ -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(),

View File

@ -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();

View File

@ -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();

View File

@ -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,
)

View File

@ -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

View File

@ -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,
)

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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,
)

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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()
}
}
};

View File

@ -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(),
}
}
}

View File

@ -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()

View File

@ -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)

View File

@ -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)*

View File

@ -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);
}

View File

@ -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()
}
}

View File

@ -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();
});
}
}

View File

@ -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()
},
)
}
}

View File

@ -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();
});
}

View File

@ -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(()),
}

View File

@ -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()
},
)

View File

@ -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);
}

View File

@ -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],
},
*/
}

View File

@ -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, _) =

View File

@ -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(),
)

View File

@ -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,
}
}
}

View File

@ -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,
}
}
}

View File

@ -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,
},

View File

@ -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 {

View File

@ -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,
},

View File

@ -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,
}
}
}

View File

@ -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,
}
}
}

View File

@ -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,

View File

@ -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());
}

View File

@ -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,
},

View File

@ -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(()),
}
}

View File

@ -57,7 +57,7 @@ impl<'a> From<SubmitSemaphoresWaitBuilder<'a>> for SubmitCommandBufferBuilder<'a
PipelineStages {
// TODO: correct stages ; hard
all_commands: true,
..PipelineStages::none()
..PipelineStages::empty()
},
);
}

View File

@ -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()),

View File

@ -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)
},
)]

View File

@ -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)]

View File

@ -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());
}
}

View File

@ -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};

View File

@ -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;
}

View File

@ -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.

View File

@ -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))
}
}

View File

@ -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 {

View File

@ -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()

View File

@ -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(

View File

@ -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.

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -108,7 +108,7 @@ pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
if aspects.plane0 {
ImageAspects {
plane0: true,
..ImageAspects::none()
..ImageAspects::empty()
}
} else {
aspects

View File

@ -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],
},
*/
}

View File

@ -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

View File

@ -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(|_| {}))
},
)

View File

@ -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());
}
}

View File

@ -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),

View File

@ -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
View 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,
}

View File

@ -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`

View File

@ -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)
},

View File

@ -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(),

View File

@ -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| {

View File

@ -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,
}

View File

@ -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,
}
}
}

View File

@ -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