use std::error;
use std::fmt;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use Error;
use OomError;
use VulkanObject;
use check_errors;
use device::Device;
use device::DeviceOwned;
use vk;
pub use pipeline::depth_stencil::Compare;
pub struct Sampler {
sampler: vk::Sampler,
device: Arc<Device>,
compare_mode: bool,
unnormalized: bool,
usable_with_float_formats: bool,
usable_with_int_formats: bool,
usable_with_swizzling: bool,
}
impl Sampler {
#[inline]
pub fn simple_repeat_linear(device: Arc<Device>) -> Arc<Sampler> {
Sampler::new(device,
Filter::Linear,
Filter::Linear,
MipmapMode::Linear,
SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat,
0.0,
1.0,
0.0,
1_000.0)
.unwrap()
}
#[inline]
pub fn simple_repeat_linear_no_mipmap(device: Arc<Device>) -> Arc<Sampler> {
Sampler::new(device,
Filter::Linear,
Filter::Linear,
MipmapMode::Nearest,
SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat,
0.0,
1.0,
0.0,
1.0)
.unwrap()
}
#[inline(always)]
pub fn new(device: Arc<Device>, mag_filter: Filter, min_filter: Filter,
mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
max_anisotropy: f32, min_lod: f32, max_lod: f32)
-> Result<Arc<Sampler>, SamplerCreationError> {
Sampler::new_impl(device,
mag_filter,
min_filter,
mipmap_mode,
address_u,
address_v,
address_w,
mip_lod_bias,
max_anisotropy,
min_lod,
max_lod,
None)
}
#[inline(always)]
pub fn compare(device: Arc<Device>, mag_filter: Filter, min_filter: Filter,
mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
address_v: SamplerAddressMode, address_w: SamplerAddressMode,
mip_lod_bias: f32, max_anisotropy: f32, min_lod: f32, max_lod: f32,
compare: Compare)
-> Result<Arc<Sampler>, SamplerCreationError> {
Sampler::new_impl(device,
mag_filter,
min_filter,
mipmap_mode,
address_u,
address_v,
address_w,
mip_lod_bias,
max_anisotropy,
min_lod,
max_lod,
Some(compare))
}
fn new_impl(device: Arc<Device>, mag_filter: Filter, min_filter: Filter,
mipmap_mode: MipmapMode, address_u: SamplerAddressMode,
address_v: SamplerAddressMode, address_w: SamplerAddressMode, mip_lod_bias: f32,
max_anisotropy: f32, min_lod: f32, max_lod: f32, compare: Option<Compare>)
-> Result<Arc<Sampler>, SamplerCreationError> {
assert!(max_anisotropy >= 1.0);
assert!(min_lod <= max_lod);
if max_anisotropy > 1.0 {
if !device.enabled_features().sampler_anisotropy {
return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
}
let limit = device.physical_device().limits().max_sampler_anisotropy();
if max_anisotropy > limit {
return Err(SamplerCreationError::AnisotropyLimitExceeded {
requested: max_anisotropy,
maximum: limit,
});
}
}
{
let limit = device.physical_device().limits().max_sampler_lod_bias();
if mip_lod_bias > limit {
return Err(SamplerCreationError::MipLodBiasLimitExceeded {
requested: mip_lod_bias,
maximum: limit,
});
}
}
if [address_u, address_v, address_w]
.iter()
.any(|&mode| mode == SamplerAddressMode::MirrorClampToEdge)
{
if !device.loaded_extensions().khr_sampler_mirror_clamp_to_edge {
return Err(SamplerCreationError::SamplerMirrorClampToEdgeExtensionNotEnabled);
}
}
let border_color = address_u.border_color();
let border_color = match (border_color, address_v.border_color()) {
(Some(b1), Some(b2)) => {
assert_eq!(b1, b2);
Some(b1)
},
(None, b) => b,
(b, None) => b,
};
let border_color = match (border_color, address_w.border_color()) {
(Some(b1), Some(b2)) => {
assert_eq!(b1, b2);
Some(b1)
},
(None, b) => b,
(b, None) => b,
};
let vk = device.pointers();
let sampler = unsafe {
let infos = vk::SamplerCreateInfo {
sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
pNext: ptr::null(),
flags: 0,
magFilter: mag_filter as u32,
minFilter: min_filter as u32,
mipmapMode: mipmap_mode as u32,
addressModeU: address_u.to_vk(),
addressModeV: address_v.to_vk(),
addressModeW: address_w.to_vk(),
mipLodBias: mip_lod_bias,
anisotropyEnable: if max_anisotropy > 1.0 {
vk::TRUE
} else {
vk::FALSE
},
maxAnisotropy: max_anisotropy,
compareEnable: if compare.is_some() {
vk::TRUE
} else {
vk::FALSE
},
compareOp: compare.map(|c| c as u32).unwrap_or(0),
minLod: min_lod,
maxLod: max_lod,
borderColor: border_color.map(|b| b as u32).unwrap_or(0),
unnormalizedCoordinates: vk::FALSE,
};
let mut output = MaybeUninit::uninit();
check_errors(vk.CreateSampler(device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr()))?;
output.assume_init()
};
Ok(Arc::new(Sampler {
sampler: sampler,
device: device.clone(),
compare_mode: compare.is_some(),
unnormalized: false,
usable_with_float_formats: match border_color {
Some(BorderColor::FloatTransparentBlack) => true,
Some(BorderColor::FloatOpaqueBlack) => true,
Some(BorderColor::FloatOpaqueWhite) => true,
Some(_) => false,
None => true,
},
usable_with_int_formats: compare.is_none() &&
match border_color {
Some(BorderColor::IntTransparentBlack) => true,
Some(BorderColor::IntOpaqueBlack) => true,
Some(BorderColor::IntOpaqueWhite) => true,
Some(_) => false,
None => true,
},
usable_with_swizzling: match border_color {
Some(BorderColor::FloatOpaqueBlack) => false,
Some(BorderColor::IntOpaqueBlack) => false,
_ => true,
},
}))
}
pub fn unnormalized(device: Arc<Device>, filter: Filter,
address_u: UnnormalizedSamplerAddressMode,
address_v: UnnormalizedSamplerAddressMode)
-> Result<Arc<Sampler>, SamplerCreationError> {
let vk = device.pointers();
let border_color = address_u.border_color();
let border_color = match (border_color, address_v.border_color()) {
(Some(b1), Some(b2)) => {
assert_eq!(b1, b2);
Some(b1)
},
(None, b) => b,
(b, None) => b,
};
let sampler = unsafe {
let infos = vk::SamplerCreateInfo {
sType: vk::STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
pNext: ptr::null(),
flags: 0,
magFilter: filter as u32,
minFilter: filter as u32,
mipmapMode: vk::SAMPLER_MIPMAP_MODE_NEAREST,
addressModeU: address_u.to_vk(),
addressModeV: address_v.to_vk(),
addressModeW: vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
mipLodBias: 0.0,
anisotropyEnable: vk::FALSE,
maxAnisotropy: 1.0,
compareEnable: vk::FALSE,
compareOp: vk::COMPARE_OP_NEVER,
minLod: 0.0,
maxLod: 0.0,
borderColor: border_color.map(|b| b as u32).unwrap_or(0),
unnormalizedCoordinates: vk::TRUE,
};
let mut output = MaybeUninit::uninit();
check_errors(vk.CreateSampler(device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr()))?;
output.assume_init()
};
Ok(Arc::new(Sampler {
sampler: sampler,
device: device.clone(),
compare_mode: false,
unnormalized: true,
usable_with_float_formats: match border_color {
Some(BorderColor::FloatTransparentBlack) => true,
Some(BorderColor::FloatOpaqueBlack) => true,
Some(BorderColor::FloatOpaqueWhite) => true,
Some(_) => false,
None => true,
},
usable_with_int_formats: match border_color {
Some(BorderColor::IntTransparentBlack) => true,
Some(BorderColor::IntOpaqueBlack) => true,
Some(BorderColor::IntOpaqueWhite) => true,
Some(_) => false,
None => true,
},
usable_with_swizzling: match border_color {
Some(BorderColor::FloatOpaqueBlack) => false,
Some(BorderColor::IntOpaqueBlack) => false,
_ => true,
},
}))
}
#[inline]
pub fn compare_mode(&self) -> bool {
self.compare_mode
}
#[inline]
pub fn is_unnormalized(&self) -> bool {
self.unnormalized
}
#[inline]
pub fn usable_with_float_formats(&self) -> bool {
self.usable_with_float_formats
}
#[inline]
pub fn usable_with_int_formats(&self) -> bool {
self.usable_with_int_formats
}
#[inline]
pub fn usable_with_swizzling(&self) -> bool {
self.usable_with_swizzling
}
}
unsafe impl DeviceOwned for Sampler {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl VulkanObject for Sampler {
type Object = vk::Sampler;
const TYPE: vk::ObjectType = vk::OBJECT_TYPE_SAMPLER;
#[inline]
fn internal_object(&self) -> vk::Sampler {
self.sampler
}
}
impl fmt::Debug for Sampler {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan sampler {:?}>", self.sampler)
}
}
impl Drop for Sampler {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
vk.DestroySampler(self.device.internal_object(), self.sampler, ptr::null());
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum Filter {
Linear = vk::FILTER_LINEAR,
Nearest = vk::FILTER_NEAREST,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum MipmapMode {
Nearest = vk::SAMPLER_MIPMAP_MODE_NEAREST,
Linear = vk::SAMPLER_MIPMAP_MODE_LINEAR,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum SamplerAddressMode {
Repeat,
MirroredRepeat,
ClampToEdge,
ClampToBorder(BorderColor),
MirrorClampToEdge,
}
impl SamplerAddressMode {
#[inline]
fn to_vk(self) -> vk::SamplerAddressMode {
match self {
SamplerAddressMode::Repeat => vk::SAMPLER_ADDRESS_MODE_REPEAT,
SamplerAddressMode::MirroredRepeat => vk::SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
SamplerAddressMode::ClampToEdge => vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
SamplerAddressMode::ClampToBorder(_) => vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
SamplerAddressMode::MirrorClampToEdge => vk::SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
}
}
#[inline]
fn border_color(self) -> Option<BorderColor> {
match self {
SamplerAddressMode::ClampToBorder(c) => Some(c),
_ => None,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum UnnormalizedSamplerAddressMode {
ClampToEdge,
ClampToBorder(BorderColor),
}
impl UnnormalizedSamplerAddressMode {
#[inline]
fn to_vk(self) -> vk::SamplerAddressMode {
match self {
UnnormalizedSamplerAddressMode::ClampToEdge => vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
UnnormalizedSamplerAddressMode::ClampToBorder(_) => {
vk::SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
},
}
}
#[inline]
fn border_color(self) -> Option<BorderColor> {
match self {
UnnormalizedSamplerAddressMode::ClampToEdge => None,
UnnormalizedSamplerAddressMode::ClampToBorder(c) => Some(c),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum BorderColor {
FloatTransparentBlack = vk::BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
IntTransparentBlack = vk::BORDER_COLOR_INT_TRANSPARENT_BLACK,
FloatOpaqueBlack = vk::BORDER_COLOR_FLOAT_OPAQUE_BLACK,
IntOpaqueBlack = vk::BORDER_COLOR_INT_OPAQUE_BLACK,
FloatOpaqueWhite = vk::BORDER_COLOR_FLOAT_OPAQUE_WHITE,
IntOpaqueWhite = vk::BORDER_COLOR_INT_OPAQUE_WHITE,
}
#[derive(Clone, Debug, PartialEq)]
pub enum SamplerCreationError {
OomError(OomError),
TooManyObjects,
SamplerAnisotropyFeatureNotEnabled,
AnisotropyLimitExceeded {
requested: f32,
maximum: f32,
},
MipLodBiasLimitExceeded {
requested: f32,
maximum: f32,
},
SamplerMirrorClampToEdgeExtensionNotEnabled,
}
impl error::Error for SamplerCreationError {
#[inline]
fn description(&self) -> &str {
match *self {
SamplerCreationError::OomError(_) => "not enough memory available",
SamplerCreationError::TooManyObjects => "too many simultaneous sampler objects",
SamplerCreationError::SamplerAnisotropyFeatureNotEnabled =>
"the `sampler_anisotropy` feature is not enabled",
SamplerCreationError::AnisotropyLimitExceeded { .. } => "anisotropy limit exceeded",
SamplerCreationError::MipLodBiasLimitExceeded { .. } => "mip lod bias limit exceeded",
SamplerCreationError::SamplerMirrorClampToEdgeExtensionNotEnabled =>
"the device extension `VK_KHR_sampler_mirror_clamp_to_edge` is not enabled",
}
}
#[inline]
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
SamplerCreationError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for SamplerCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<OomError> for SamplerCreationError {
#[inline]
fn from(err: OomError) -> SamplerCreationError {
SamplerCreationError::OomError(err)
}
}
impl From<Error> for SamplerCreationError {
#[inline]
fn from(err: Error) -> SamplerCreationError {
match err {
err @ Error::OutOfHostMemory => SamplerCreationError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => SamplerCreationError::OomError(OomError::from(err)),
Error::TooManyObjects => SamplerCreationError::TooManyObjects,
_ => panic!("unexpected error: {:?}", err),
}
}
}
#[cfg(test)]
mod tests {
use sampler;
#[test]
fn create_regular() {
let (device, queue) = gfx_dev_and_queue!();
let s = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
1.0,
1.0,
0.0,
2.0)
.unwrap();
assert!(!s.compare_mode());
assert!(!s.is_unnormalized());
}
#[test]
fn create_compare() {
let (device, queue) = gfx_dev_and_queue!();
let s = sampler::Sampler::compare(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
1.0,
1.0,
0.0,
2.0,
sampler::Compare::Less)
.unwrap();
assert!(s.compare_mode());
assert!(!s.is_unnormalized());
}
#[test]
fn create_unnormalized() {
let (device, queue) = gfx_dev_and_queue!();
let s =
sampler::Sampler::unnormalized(device,
sampler::Filter::Linear,
sampler::UnnormalizedSamplerAddressMode::ClampToEdge,
sampler::UnnormalizedSamplerAddressMode::ClampToEdge)
.unwrap();
assert!(!s.compare_mode());
assert!(s.is_unnormalized());
}
#[test]
fn simple_repeat_linear() {
let (device, queue) = gfx_dev_and_queue!();
let _ = sampler::Sampler::simple_repeat_linear(device);
}
#[test]
fn simple_repeat_linear_no_mipmap() {
let (device, queue) = gfx_dev_and_queue!();
let _ = sampler::Sampler::simple_repeat_linear_no_mipmap(device);
}
#[test]
fn min_lod_inferior() {
let (device, queue) = gfx_dev_and_queue!();
assert_should_panic!({
let _ = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
1.0,
1.0,
5.0,
2.0);
});
}
#[test]
fn max_anisotropy() {
let (device, queue) = gfx_dev_and_queue!();
assert_should_panic!({
let _ = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
1.0,
0.5,
0.0,
2.0);
});
}
#[test]
fn different_borders() {
let (device, queue) = gfx_dev_and_queue!();
let b1 = sampler::BorderColor::IntTransparentBlack;
let b2 = sampler::BorderColor::FloatOpaqueWhite;
assert_should_panic!({
let _ = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::ClampToBorder(b1),
sampler::SamplerAddressMode::ClampToBorder(b2),
sampler::SamplerAddressMode::Repeat,
1.0,
1.0,
5.0,
2.0);
});
}
#[test]
fn anisotropy_feature() {
let (device, queue) = gfx_dev_and_queue!();
let r = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
1.0,
2.0,
0.0,
2.0);
match r {
Err(sampler::SamplerCreationError::SamplerAnisotropyFeatureNotEnabled) => (),
_ => panic!(),
}
}
#[test]
fn anisotropy_limit() {
let (device, queue) = gfx_dev_and_queue!(sampler_anisotropy);
let r = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
1.0,
100000000.0,
0.0,
2.0);
match r {
Err(sampler::SamplerCreationError::AnisotropyLimitExceeded { .. }) => (),
_ => panic!(),
}
}
#[test]
fn mip_lod_bias_limit() {
let (device, queue) = gfx_dev_and_queue!();
let r = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
sampler::SamplerAddressMode::Repeat,
100000000.0,
1.0,
0.0,
2.0);
match r {
Err(sampler::SamplerCreationError::MipLodBiasLimitExceeded { .. }) => (),
_ => panic!(),
}
}
#[test]
fn sampler_mirror_clamp_to_edge_extension() {
let (device, queue) = gfx_dev_and_queue!();
let r = sampler::Sampler::new(device,
sampler::Filter::Linear,
sampler::Filter::Linear,
sampler::MipmapMode::Nearest,
sampler::SamplerAddressMode::MirrorClampToEdge,
sampler::SamplerAddressMode::MirrorClampToEdge,
sampler::SamplerAddressMode::MirrorClampToEdge,
1.0,
1.0,
0.0,
2.0);
match r {
Err(sampler::SamplerCreationError::SamplerMirrorClampToEdgeExtensionNotEnabled) => (),
_ => panic!(),
}
}
}