#[doc(inline)]
pub use vulkano::*;
pub use vulkano::{
buffer::cpu_pool::{CpuBufferPoolChunk, CpuBufferPoolSubbuffer},
buffer::{
BufferAccess, BufferCreationError, BufferInner, BufferSlice, BufferUsage, BufferView,
BufferViewRef, CpuAccessibleBuffer, CpuBufferPool, DeviceLocalBuffer, ImmutableBuffer,
TypedBufferAccess,
},
command_buffer::{
AutoCommandBuffer, AutoCommandBufferBuilder, AutoCommandBufferBuilderContextError,
CommandBuffer, CommandBufferExecFuture, DispatchIndirectCommand, DrawIndirectCommand,
DynamicState, ExecuteCommandsError, StateCacherOutcome, UpdateBufferError,
},
descriptor::descriptor::{
DescriptorBufferDesc, DescriptorDesc, DescriptorDescSupersetError, DescriptorDescTy,
DescriptorImageDesc, DescriptorImageDescArray, DescriptorImageDescDimensions,
DescriptorType, ShaderStages, ShaderStagesSupersetError,
},
descriptor::descriptor_set::{
DescriptorPool, DescriptorPoolAlloc, DescriptorPoolAllocError, DescriptorSetDesc,
DescriptorSetsCollection, DescriptorWrite, DescriptorsCount, FixedSizeDescriptorSet,
FixedSizeDescriptorSetBuilder, FixedSizeDescriptorSetBuilderArray,
FixedSizeDescriptorSetsPool, PersistentDescriptorSet, PersistentDescriptorSetBuf,
PersistentDescriptorSetBufView, PersistentDescriptorSetBuildError,
PersistentDescriptorSetBuilder, PersistentDescriptorSetBuilderArray,
PersistentDescriptorSetError, PersistentDescriptorSetImg, PersistentDescriptorSetSampler,
StdDescriptorPool, StdDescriptorPoolAlloc, UnsafeDescriptorPool,
UnsafeDescriptorPoolAllocIter, UnsafeDescriptorSet, UnsafeDescriptorSetLayout,
},
descriptor::pipeline_layout::{
EmptyPipelineDesc, PipelineLayout, PipelineLayoutCreationError, PipelineLayoutDesc,
PipelineLayoutDescPcRange, PipelineLayoutDescUnion, PipelineLayoutLimitsError,
PipelineLayoutNotSupersetError, PipelineLayoutPushConstantsCompatible,
PipelineLayoutSetsCompatible, PipelineLayoutSuperset, PipelineLayoutSys,
RuntimePipelineDesc, RuntimePipelineDescError,
},
descriptor::{DescriptorSet, PipelineLayoutAbstract},
device::{
Device, DeviceCreationError, DeviceExtensions, DeviceOwned, Queue, QueuesIter,
RawDeviceExtensions,
},
format::{
AcceptsPixels, ClearValue, ClearValuesTuple, Format, FormatDesc, FormatTy,
PossibleCompressedFormatDesc, PossibleDepthFormatDesc, PossibleDepthStencilFormatDesc,
PossibleFloatFormatDesc, PossibleFloatOrCompressedFormatDesc, PossibleSintFormatDesc,
PossibleStencilFormatDesc, PossibleUintFormatDesc, StrongStorage,
},
framebuffer::{
AttachmentDescription, AttachmentsList, Framebuffer, FramebufferAbstract,
FramebufferBuilder, FramebufferCreationError, FramebufferSys,
IncompatibleRenderPassAttachmentError, LoadOp, PassDependencyDescription, PassDescription,
RenderPass, RenderPassAbstract, RenderPassCompatible, RenderPassCreationError,
RenderPassDesc, RenderPassDescAttachments, RenderPassDescClearValues,
RenderPassDescDependencies, RenderPassDescSubpasses, RenderPassSubpassInterface,
RenderPassSys, StoreOp, Subpass, SubpassContents,
},
image::immutable::ImmutableImageInitialization,
image::traits::{
AttachmentImageView, ImageAccessFromUndefinedLayout, ImageClearValue, ImageContent,
},
image::{
AttachmentImage, ImageAccess, ImageCreationError, ImageDimensions, ImageInner, ImageLayout,
ImageUsage, ImageViewAccess, ImmutableImage, MipmapsCount, StorageImage, SwapchainImage,
},
instance::{
ApplicationInfo, Instance, InstanceCreationError, InstanceExtensions, Limits,
PhysicalDevice, PhysicalDeviceType, PhysicalDevicesIter, QueueFamiliesIter, QueueFamily,
RawInstanceExtensions, Version,
},
pipeline::blend::{AttachmentBlend, AttachmentsBlend, Blend, BlendFactor, BlendOp, LogicOp},
pipeline::depth_stencil::{DepthBounds, DepthStencil, Stencil, StencilOp},
pipeline::vertex::{
AttributeInfo, BufferlessDefinition, BufferlessVertices, IncompatibleVertexDefinitionError,
OneVertexOneInstanceDefinition, SingleBufferDefinition, SingleInstanceBufferDefinition,
TwoBuffersDefinition, Vertex, VertexDefinition, VertexMember, VertexMemberInfo,
VertexMemberTy, VertexSource,
},
pipeline::viewport::{Scissor, Viewport, ViewportsState},
pipeline::{
ComputePipeline, ComputePipelineAbstract, ComputePipelineCreationError, ComputePipelineSys,
GraphicsPipeline, GraphicsPipelineAbstract, GraphicsPipelineBuilder,
GraphicsPipelineCreationError, GraphicsPipelineSys,
},
query::{
OcclusionQueriesPool, QueryPipelineStatisticFlags, QueryPoolCreationError, QueryType,
UnsafeQueriesRange, UnsafeQuery, UnsafeQueryPool,
},
sampler::{
Compare as DepthStencilCompare, Sampler, SamplerAddressMode, SamplerCreationError,
UnnormalizedSamplerAddressMode,
},
swapchain::{Surface, Swapchain, SwapchainAcquireFuture, SwapchainCreationError},
sync::{
Fence, FenceSignalFuture, GpuFuture, JoinFuture, NowFuture, Semaphore,
SemaphoreSignalFuture,
},
};
pub use vulkano_shaders as shaders;
pub use vulkano_win as win;
use crate::vk;
use crate::vk::instance::debug::{
DebugCallback, DebugCallbackCreationError, Message, MessageTypes,
};
use crate::vk::instance::loader::{FunctionPointers, Loader};
use std::borrow::Cow;
use std::ops::{self, Range};
use std::panic::RefUnwindSafe;
use std::sync::Arc;
#[cfg(all(target_os = "macos", not(test)))]
use moltenvk_deps;
#[cfg(all(target_os = "macos", not(test)))]
use vulkano::instance::loader::DynamicLibraryLoader;
pub const DEFAULT_APPLICATION_NAME: &'static str = "nannou-app";
pub const DEFAULT_APPLICATION_INFO: ApplicationInfo<'static> = ApplicationInfo {
application_name: Some(Cow::Borrowed(DEFAULT_APPLICATION_NAME)),
application_version: None,
engine_name: None,
engine_version: None,
};
#[derive(Default)]
pub struct FramebufferObject {
framebuffer: Option<Arc<FramebufferAbstract + Send + Sync>>,
}
pub type Fbo = FramebufferObject;
pub type FramebufferBuilderResult<R, A> =
Result<FramebufferBuilder<R, A>, FramebufferCreationError>;
#[derive(Default)]
pub struct InstanceBuilder {
pub app_info: Option<ApplicationInfo<'static>>,
pub extensions: Option<InstanceExtensions>,
pub layers: Vec<String>,
pub loader: Option<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
}
#[derive(Default)]
pub struct DebugCallbackBuilder {
pub message_types: Option<MessageTypes>,
pub user_callback: Option<BoxedUserCallback>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct SamplerBuilder {
pub mag_filter: Option<vk::sampler::Filter>,
pub min_filter: Option<vk::sampler::Filter>,
pub mipmap_mode: Option<vk::sampler::MipmapMode>,
pub address_u: Option<SamplerAddressMode>,
pub address_v: Option<SamplerAddressMode>,
pub address_w: Option<SamplerAddressMode>,
pub mip_lod_bias: Option<f32>,
pub max_anisotropy: Option<f32>,
pub min_lod: Option<f32>,
pub max_lod: Option<f32>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct ViewportBuilder {
pub origin: Option<[f32; 2]>,
pub depth_range: Option<Range<f32>>,
}
pub trait DynamicStateBuilder {
fn line_width(self, line_width: f32) -> Self;
fn viewports(self, viewports: Vec<Viewport>) -> Self;
fn scissors(self, scissors: Vec<Scissor>) -> Self;
}
impl DynamicStateBuilder for DynamicState {
fn line_width(mut self, line_width: f32) -> Self {
self.line_width = Some(line_width);
self
}
fn viewports(mut self, viewports: Vec<Viewport>) -> Self {
self.viewports = Some(viewports);
self
}
fn scissors(mut self, scissors: Vec<Scissor>) -> Self {
self.scissors = Some(scissors);
self
}
}
type BoxedUserCallback = Box<Fn(&Message) + 'static + Send + RefUnwindSafe>;
impl FramebufferObject {
pub fn inner(&self) -> &Option<Arc<FramebufferAbstract + Send + Sync>> {
&self.framebuffer
}
pub fn update<R, F, A>(
&mut self,
render_pass: R,
dimensions: [u32; 3],
builder: F,
) -> Result<(), FramebufferCreationError>
where
R: 'static + vk::framebuffer::RenderPassAbstract + Send + Sync,
F: FnOnce(FramebufferBuilder<R, ()>) -> FramebufferBuilderResult<R, A>,
A: 'static + vk::framebuffer::AttachmentsList + Send + Sync,
{
let needs_creation = self.framebuffer.is_none()
|| !self.dimensions_match(dimensions)
|| !self.render_passes_match(&render_pass);
if needs_creation {
let builder = builder(Framebuffer::start(render_pass))?;
let fb = builder.build()?;
self.framebuffer = Some(Arc::new(fb));
}
Ok(())
}
pub fn expect_inner(&self) -> Arc<FramebufferAbstract + Send + Sync> {
self.framebuffer
.as_ref()
.expect("inner framebuffer was `None` - you must call the `update` method first")
.clone()
}
pub fn render_passes_match<R>(&self, render_pass: R) -> bool
where
R: vk::framebuffer::RenderPassAbstract,
{
self.framebuffer
.as_ref()
.map(|fb| vk::framebuffer::RenderPassAbstract::inner(fb).internal_object())
.map(|obj| obj == render_pass.inner().internal_object())
.unwrap_or(false)
}
pub fn dimensions_match(&self, dimensions: [u32; 3]) -> bool {
self.framebuffer
.as_ref()
.map(|fb| fb.dimensions() == dimensions)
.unwrap_or(false)
}
}
impl InstanceBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn app_info(mut self, app_info: ApplicationInfo<'static>) -> Self {
self.app_info = Some(app_info);
self
}
pub fn extensions(mut self, extensions: InstanceExtensions) -> Self {
self.extensions = Some(extensions);
self
}
pub fn add_extensions(mut self, ext: InstanceExtensions) -> Self {
self.extensions = self
.extensions
.take()
.map(|mut e| {
e.khr_surface |= ext.khr_surface;
e.khr_display |= ext.khr_display;
e.khr_xlib_surface |= ext.khr_xlib_surface;
e.khr_xcb_surface |= ext.khr_xcb_surface;
e.khr_wayland_surface |= ext.khr_wayland_surface;
e.khr_android_surface |= ext.khr_android_surface;
e.khr_win32_surface |= ext.khr_win32_surface;
e.ext_debug_report |= ext.ext_debug_report;
e.mvk_ios_surface |= ext.mvk_ios_surface;
e.mvk_macos_surface |= ext.mvk_macos_surface;
e.mvk_moltenvk |= ext.mvk_moltenvk;
e.nn_vi_surface |= ext.nn_vi_surface;
e.ext_swapchain_colorspace |= ext.ext_swapchain_colorspace;
e.khr_get_physical_device_properties2 |= ext.khr_get_physical_device_properties2;
e
})
.or(Some(ext));
self
}
pub fn layers<L>(mut self, layers: L) -> Self
where
L: IntoIterator,
L::Item: Into<String>,
{
self.layers = layers.into_iter().map(Into::into).collect();
self
}
pub fn add_layers<L>(mut self, layers: L) -> Self
where
L: IntoIterator,
L::Item: Into<String>,
{
self.layers.extend(layers.into_iter().map(Into::into));
self
}
pub fn add_loader(mut self, loader: FunctionPointers<Box<dyn Loader + Send + Sync>>) -> Self {
self.loader = Some(loader);
self
}
pub fn build(self) -> Result<Arc<Instance>, InstanceCreationError> {
let InstanceBuilder {
app_info,
extensions,
layers,
loader,
} = self;
let app_info = app_info.unwrap_or(DEFAULT_APPLICATION_INFO);
let extensions = extensions.unwrap_or_else(required_windowing_extensions);
let layers = layers.iter().map(|s| &s[..]);
match loader {
None => Instance::new(Some(&app_info), &extensions, layers),
Some(loader) => Instance::with_loader(loader, Some(&app_info), &extensions, layers),
}
}
}
impl DebugCallbackBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn message_types(mut self, msg_tys: MessageTypes) -> Self {
self.message_types = Some(msg_tys);
self
}
pub fn user_callback<F>(mut self, cb: F) -> Self
where
F: Fn(&Message) + 'static + Send + RefUnwindSafe,
{
self.user_callback = Some(Box::new(cb) as Box<_>);
self
}
pub fn build(
self,
instance: &Arc<Instance>,
) -> Result<DebugCallback, DebugCallbackCreationError> {
let DebugCallbackBuilder {
message_types,
user_callback,
} = self;
let message_types = message_types.unwrap_or_else(|| MessageTypes {
error: true,
warning: true,
performance_warning: true,
information: true,
debug: true,
});
let user_callback = move |msg: &Message| {
match user_callback {
Some(ref cb) => (**cb)(msg),
None => {
let ty = if msg.ty.error {
"error"
} else if msg.ty.warning {
"warning"
} else if msg.ty.performance_warning {
"performance_warning"
} else if msg.ty.information {
"information"
} else if msg.ty.debug {
"debug"
} else {
println!("[vulkan] <unknown message type>");
return;
};
println!("[vulkan] {} {}: {}", msg.layer_prefix, ty, msg.description);
}
};
};
DebugCallback::new(instance, message_types, user_callback)
}
}
impl SamplerBuilder {
pub const DEFAULT_MAG_FILTER: vk::sampler::Filter = vk::sampler::Filter::Linear;
pub const DEFAULT_MIN_FILTER: vk::sampler::Filter = vk::sampler::Filter::Linear;
pub const DEFAULT_MIPMAP_MODE: vk::sampler::MipmapMode = vk::sampler::MipmapMode::Nearest;
pub const DEFAULT_ADDRESS_U: SamplerAddressMode = SamplerAddressMode::ClampToEdge;
pub const DEFAULT_ADDRESS_V: SamplerAddressMode = SamplerAddressMode::ClampToEdge;
pub const DEFAULT_ADDRESS_W: SamplerAddressMode = SamplerAddressMode::ClampToEdge;
pub const DEFAULT_MIP_LOD_BIAS: f32 = 0.0;
pub const DEFAULT_MAX_ANISOTROPY: f32 = 1.0;
pub const DEFAULT_MIN_LOD: f32 = 0.0;
pub const DEFAULT_MAX_LOD: f32 = 1.0;
pub fn new() -> Self {
Self::default()
}
pub fn mag_filter(mut self, filter: vk::sampler::Filter) -> Self {
self.mag_filter = Some(filter);
self
}
pub fn min_filter(mut self, filter: vk::sampler::Filter) -> Self {
self.min_filter = Some(filter);
self
}
pub fn mipmap_mode(mut self, mode: vk::sampler::MipmapMode) -> Self {
self.mipmap_mode = Some(mode);
self
}
pub fn address_u(mut self, mode: SamplerAddressMode) -> Self {
self.address_u = Some(mode);
self
}
pub fn address_v(mut self, mode: SamplerAddressMode) -> Self {
self.address_v = Some(mode);
self
}
pub fn address_w(mut self, mode: SamplerAddressMode) -> Self {
self.address_w = Some(mode);
self
}
pub fn mip_lod_bias(mut self, bias: f32) -> Self {
self.mip_lod_bias = Some(bias);
self
}
pub fn max_anisotropy(mut self, max: f32) -> Self {
self.max_anisotropy = Some(max);
self
}
pub fn min_lod(mut self, lod: f32) -> Self {
self.min_lod = Some(lod);
self
}
pub fn max_lod(mut self, lod: f32) -> Self {
self.max_lod = Some(lod);
self
}
pub fn build(self, device: Arc<Device>) -> Result<Arc<Sampler>, SamplerCreationError> {
let SamplerBuilder {
mag_filter,
min_filter,
mipmap_mode,
address_u,
address_v,
address_w,
mip_lod_bias,
max_anisotropy,
min_lod,
max_lod,
} = self;
Sampler::new(
device,
mag_filter.unwrap_or(Self::DEFAULT_MAG_FILTER),
min_filter.unwrap_or(Self::DEFAULT_MIN_FILTER),
mipmap_mode.unwrap_or(Self::DEFAULT_MIPMAP_MODE),
address_u.unwrap_or(Self::DEFAULT_ADDRESS_U),
address_v.unwrap_or(Self::DEFAULT_ADDRESS_V),
address_w.unwrap_or(Self::DEFAULT_ADDRESS_W),
mip_lod_bias.unwrap_or(Self::DEFAULT_MIP_LOD_BIAS),
max_anisotropy.unwrap_or(Self::DEFAULT_MAX_ANISOTROPY),
min_lod.unwrap_or(Self::DEFAULT_MIN_LOD),
max_lod.unwrap_or(Self::DEFAULT_MAX_LOD),
)
}
}
impl ViewportBuilder {
pub const DEFAULT_ORIGIN: [f32; 2] = [0.0; 2];
pub const DEFAULT_DEPTH_RANGE: Range<f32> = 0.0..1.0;
pub fn new() -> Self {
Self::default()
}
pub fn origin(mut self, origin: [f32; 2]) -> Self {
self.origin = Some(origin);
self
}
pub fn depth_range(mut self, range: Range<f32>) -> Self {
self.depth_range = Some(range);
self
}
pub fn build(self, dimensions: [f32; 2]) -> Viewport {
let ViewportBuilder {
origin,
depth_range,
} = self;
Viewport {
origin: origin.unwrap_or(Self::DEFAULT_ORIGIN),
depth_range: depth_range.unwrap_or(Self::DEFAULT_DEPTH_RANGE),
dimensions,
}
}
}
impl ops::Deref for FramebufferObject {
type Target = Option<Arc<FramebufferAbstract + Send + Sync>>;
fn deref(&self) -> &Self::Target {
&self.framebuffer
}
}
pub fn required_windowing_extensions() -> InstanceExtensions {
vulkano_win::required_extensions()
}
pub fn format_is_srgb(format: Format) -> bool {
use crate::vk::format::Format::*;
match format {
R8Srgb
| R8G8Srgb
| R8G8B8Srgb
| B8G8R8Srgb
| R8G8B8A8Srgb
| B8G8R8A8Srgb
| A8B8G8R8SrgbPack32
| BC1_RGBSrgbBlock
| BC1_RGBASrgbBlock
| BC2SrgbBlock
| BC3SrgbBlock
| BC7SrgbBlock
| ETC2_R8G8B8SrgbBlock
| ETC2_R8G8B8A1SrgbBlock
| ETC2_R8G8B8A8SrgbBlock
| ASTC_4x4SrgbBlock
| ASTC_5x4SrgbBlock
| ASTC_5x5SrgbBlock
| ASTC_6x5SrgbBlock
| ASTC_6x6SrgbBlock
| ASTC_8x5SrgbBlock
| ASTC_8x6SrgbBlock
| ASTC_8x8SrgbBlock
| ASTC_10x5SrgbBlock
| ASTC_10x6SrgbBlock
| ASTC_10x8SrgbBlock
| ASTC_10x10SrgbBlock
| ASTC_12x10SrgbBlock
| ASTC_12x12SrgbBlock => true,
_ => false,
}
}
pub fn msaa_samples_limited(physical_device: &PhysicalDevice, target_msaa_samples: u32) -> u32 {
let color_limit = physical_device.limits().framebuffer_color_sample_counts();
let depth_limit = physical_device.limits().framebuffer_depth_sample_counts();
let msaa_limit = std::cmp::min(color_limit, depth_limit);
std::cmp::min(msaa_limit, target_msaa_samples)
}
#[cfg(all(target_os = "macos", not(test)))]
pub fn check_moltenvk(
vulkan_builder: InstanceBuilder,
settings: Option<moltenvk_deps::Install>,
) -> InstanceBuilder {
let settings = match settings {
Some(s) => s,
None => Default::default(),
};
let path = match moltenvk_deps::check_or_install(settings) {
Err(moltenvk_deps::Error::ResetEnvVars(p)) => Some(p),
Err(moltenvk_deps::Error::NonDefaultDir) => None,
Err(moltenvk_deps::Error::ChoseNotToInstall) => {
panic!("Moltenvk is required for Nannou on MacOS")
}
Err(e) => panic!("Moltenvk installation failed {:?}", e),
Ok(p) => Some(p),
};
let loader = path.map(|p| unsafe { DynamicLibraryLoader::new(p) });
match loader {
Some(Ok(l)) => {
let loader: FunctionPointers<Box<(dyn Loader + Send + Sync + 'static)>> =
FunctionPointers::new(Box::new(l));
let required_extensions = required_extensions_with_loader(&loader);
vulkan_builder
.extensions(required_extensions)
.add_loader(loader)
}
_ => vulkan_builder.extensions(required_windowing_extensions()),
}
}
pub fn required_extensions_with_loader<L>(ptrs: &FunctionPointers<L>) -> InstanceExtensions
where
L: Loader,
{
let ideal = InstanceExtensions {
khr_surface: true,
khr_xlib_surface: true,
khr_xcb_surface: true,
khr_wayland_surface: true,
khr_android_surface: true,
khr_win32_surface: true,
mvk_ios_surface: true,
mvk_macos_surface: true,
..InstanceExtensions::none()
};
match InstanceExtensions::supported_by_core_with_loader(ptrs) {
Ok(supported) => supported.intersection(&ideal),
Err(_) => InstanceExtensions::none(),
}
}