librashader/librashader-runtime-mtl/src/samplers.rs

86 lines
3.2 KiB
Rust
Raw Normal View History

2024-02-15 11:22:25 +11:00
use librashader_common::map::FastHashMap;
2024-02-10 10:22:14 +11:00
use librashader_common::{FilterMode, WrapMode};
use objc2::rc::Retained;
2024-02-10 10:22:14 +11:00
use objc2::runtime::ProtocolObject;
use objc2_metal::{
MTLCompareFunction, MTLDevice, MTLSamplerAddressMode, MTLSamplerBorderColor,
MTLSamplerDescriptor, MTLSamplerMinMagFilter, MTLSamplerState,
};
2024-02-10 10:22:14 +11:00
use crate::error::{FilterChainError, Result};
pub struct SamplerSet {
// todo: may need to deal with differences in mip filter.
samplers: FastHashMap<
(WrapMode, FilterMode, FilterMode),
Retained<ProtocolObject<dyn MTLSamplerState>>,
>,
2024-02-10 10:22:14 +11:00
}
impl SamplerSet {
#[inline(always)]
pub fn get(
&self,
wrap: WrapMode,
filter: FilterMode,
mipmap: FilterMode,
) -> &ProtocolObject<dyn MTLSamplerState> {
// eprintln!("{wrap}, {filter}, {mip}");
// SAFETY: the sampler set is complete for the matrix
// wrap x filter x mipmap
let id: &Retained<ProtocolObject<dyn MTLSamplerState>> = unsafe {
2024-02-10 10:22:14 +11:00
self.samplers
.get(&(wrap, filter, mipmap))
.unwrap_unchecked()
};
id.as_ref()
}
pub fn new(device: &ProtocolObject<dyn MTLDevice>) -> Result<SamplerSet> {
let mut samplers = FastHashMap::default();
2024-02-10 10:22:14 +11:00
let wrap_modes = &[
WrapMode::ClampToBorder,
WrapMode::ClampToEdge,
WrapMode::Repeat,
WrapMode::MirroredRepeat,
];
for wrap_mode in wrap_modes {
for filter_mode in &[FilterMode::Linear, FilterMode::Nearest] {
for mipmap_filter in &[FilterMode::Linear, FilterMode::Nearest] {
let descriptor = MTLSamplerDescriptor::new();
descriptor.setRAddressMode(MTLSamplerAddressMode::from(*wrap_mode));
descriptor.setSAddressMode(MTLSamplerAddressMode::from(*wrap_mode));
descriptor.setTAddressMode(MTLSamplerAddressMode::from(*wrap_mode));
descriptor.setMagFilter(MTLSamplerMinMagFilter::from(*filter_mode));
descriptor.setMinFilter(MTLSamplerMinMagFilter::from(*filter_mode));
descriptor.setMipFilter(filter_mode.mtl_mip(*mipmap_filter));
descriptor.setLodMinClamp(0.0);
descriptor.setLodMaxClamp(1000.0);
descriptor.setCompareFunction(MTLCompareFunction::Never);
2024-02-10 10:22:14 +11:00
descriptor.setMaxAnisotropy(1);
descriptor.setBorderColor(MTLSamplerBorderColor::TransparentBlack);
2024-02-10 10:22:14 +11:00
descriptor.setNormalizedCoordinates(true);
let Some(sampler_state) = device.newSamplerStateWithDescriptor(&descriptor)
else {
return Err(FilterChainError::SamplerError(
*wrap_mode,
*filter_mode,
*mipmap_filter,
));
};
samplers.insert((*wrap_mode, *filter_mode, *mipmap_filter), sampler_state);
}
}
}
// assert all samplers were created.
assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2);
Ok(SamplerSet { samplers })
}
}