rt(mtl): common + shaderset for metal
This commit is contained in:
parent
d5ef5904f3
commit
12d55e928e
|
@ -13,7 +13,7 @@ members = [
|
||||||
"librashader-cache",
|
"librashader-cache",
|
||||||
"librashader-capi",
|
"librashader-capi",
|
||||||
"librashader-build-script"
|
"librashader-build-script"
|
||||||
, "librashader-runtime-wgpu"]
|
, "librashader-runtime-wgpu", "librashader-runtime-metal"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.metadata.release]
|
[workspace.metadata.release]
|
||||||
|
|
|
@ -19,6 +19,7 @@ d3d12 = ["windows", "dxgi"]
|
||||||
dxgi = ["windows"]
|
dxgi = ["windows"]
|
||||||
vulkan = ["ash"]
|
vulkan = ["ash"]
|
||||||
wgpu = ["wgpu-types"]
|
wgpu = ["wgpu-types"]
|
||||||
|
metal = ["icrate"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gl = { version = "0.14.0", optional = true }
|
gl = { version = "0.14.0", optional = true }
|
||||||
|
@ -37,3 +38,8 @@ features = [
|
||||||
"Win32_Graphics_Direct3D11",
|
"Win32_Graphics_Direct3D11",
|
||||||
"Win32_Graphics_Direct3D12",
|
"Win32_Graphics_Direct3D12",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[target.'cfg(macos)'.dependencies.icrate]
|
||||||
|
optional = true
|
||||||
|
version = "0.1.0"
|
||||||
|
features = ["Metal"]
|
|
@ -24,8 +24,12 @@ pub mod d3d11;
|
||||||
#[cfg(all(target_os = "windows", feature = "d3d12"))]
|
#[cfg(all(target_os = "windows", feature = "d3d12"))]
|
||||||
pub mod d3d12;
|
pub mod d3d12;
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "macos", feature = "metal"))]
|
||||||
|
pub mod metal;
|
||||||
|
|
||||||
mod viewport;
|
mod viewport;
|
||||||
|
|
||||||
|
|
||||||
pub use viewport::Viewport;
|
pub use viewport::Viewport;
|
||||||
|
|
||||||
use num_traits::AsPrimitive;
|
use num_traits::AsPrimitive;
|
||||||
|
|
95
librashader-common/src/metal.rs
Normal file
95
librashader-common/src/metal.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
use icrate::Metal;
|
||||||
|
use crate::{Size, ImageFormat, FilterMode, WrapMode};
|
||||||
|
|
||||||
|
impl From<ImageFormat> for Metal::MTLPixelFormat {
|
||||||
|
fn from(format: ImageFormat) -> Self {
|
||||||
|
match format {
|
||||||
|
ImageFormat::Unknown => 0 as Metal::MTLPixelFormat,
|
||||||
|
ImageFormat::R8Unorm => Metal::MTLPixelFormatR8Unorm,
|
||||||
|
ImageFormat::R8Uint => Metal::MTLPixelFormatR8Uint,
|
||||||
|
ImageFormat::R8Sint => Metal::MTLPixelFormatR8Sint,
|
||||||
|
ImageFormat::R8G8Unorm => Metal::MTLPixelFormatRG8Unorm,
|
||||||
|
ImageFormat::R8G8Uint => Metal::MTLPixelFormatRG8Uint,
|
||||||
|
ImageFormat::R8G8Sint => Metal::MTLPixelFormatRG8Sint,
|
||||||
|
ImageFormat::R8G8B8A8Unorm => Metal::MTLPixelFormatRGBA8Unorm,
|
||||||
|
ImageFormat::R8G8B8A8Uint => Metal::MTLPixelFormatRGBA8Uint,
|
||||||
|
ImageFormat::R8G8B8A8Sint => Metal::MTLPixelFormatRGBA8Sint,
|
||||||
|
ImageFormat::R8G8B8A8Srgb => Metal::MTLPixelFormatRGBA8Unorm_sRGB,
|
||||||
|
ImageFormat::A2B10G10R10UnormPack32 => Metal::MTLPixelFormatRGB10A2Unorm,
|
||||||
|
ImageFormat::A2B10G10R10UintPack32 => Metal::MTLPixelFormatRGB10A2Uint,
|
||||||
|
ImageFormat::R16Uint => Metal::MTLPixelFormatR16Uint,
|
||||||
|
ImageFormat::R16Sint => Metal::MTLPixelFormatR16Sint,
|
||||||
|
ImageFormat::R16Sfloat => Metal::MTLPixelFormatR16Float,
|
||||||
|
ImageFormat::R16G16Uint => Metal::MTLPixelFormatRG16Uint,
|
||||||
|
ImageFormat::R16G16Sint => Metal::MTLPixelFormatRG16Sint,
|
||||||
|
ImageFormat::R16G16Sfloat => Metal::MTLPixelFormatRG16Float,
|
||||||
|
ImageFormat::R16G16B16A16Uint => Metal::MTLPixelFormatRGBA16Uint,
|
||||||
|
ImageFormat::R16G16B16A16Sint => Metal::MTLPixelFormatRGBA16Sint,
|
||||||
|
ImageFormat::R16G16B16A16Sfloat => Metal::MTLPixelFormatRGBA16Float,
|
||||||
|
ImageFormat::R32Uint => Metal::MTLPixelFormatR32Uint,
|
||||||
|
ImageFormat::R32Sint => Metal::MTLPixelFormatR32Sint,
|
||||||
|
ImageFormat::R32Sfloat => Metal::MTLPixelFormatR32Float,
|
||||||
|
ImageFormat::R32G32Uint => Metal::MTLPixelFormatRG32Uint,
|
||||||
|
ImageFormat::R32G32Sint => Metal::MTLPixelFormatRG32Sint,
|
||||||
|
ImageFormat::R32G32Sfloat => Metal::MTLPixelFormatRG32Float,
|
||||||
|
ImageFormat::R32G32B32A32Uint => Metal::MTLPixelFormatRGBA32Uint,
|
||||||
|
ImageFormat::R32G32B32A32Sint => Metal::MTLPixelFormatRGBA32Sint,
|
||||||
|
ImageFormat::R32G32B32A32Sfloat => Metal::MTLPixelFormatRGBA32Float,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Metal::MTLViewport> for Size<u32> {
|
||||||
|
fn from(value: Metal::MTLViewport) -> Self {
|
||||||
|
Size {
|
||||||
|
width: value.width as u32,
|
||||||
|
height: value.height as u32,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size<u32>> for Metal::MTLViewport {
|
||||||
|
fn from(value: Size<u32>) -> Self {
|
||||||
|
Metal::MTLViewport {
|
||||||
|
originX: 0.0,
|
||||||
|
originY: 0.0,
|
||||||
|
width: value.width as f64,
|
||||||
|
height: value.height as f64,
|
||||||
|
znear: -1.0,
|
||||||
|
zfar: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl From<WrapMode> for Metal::MTLSamplerAddressMode {
|
||||||
|
fn from(value: WrapMode) -> Self {
|
||||||
|
match value {
|
||||||
|
WrapMode::ClampToBorder => Metal::MTLSamplerAddressModeClampToBorderColor,
|
||||||
|
WrapMode::ClampToEdge => Metal::MTLSamplerAddressModeClampToEdge,
|
||||||
|
WrapMode::Repeat => Metal::MTLSamplerAddressModeRepeat,
|
||||||
|
WrapMode::MirroredRepeat => Metal::MTLSamplerAddressModeMirrorRepeat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FilterMode> for Metal::MTLSamplerMinMagFilter {
|
||||||
|
fn from(value: FilterMode) -> Self {
|
||||||
|
match value {
|
||||||
|
FilterMode::Linear => Metal::MTLSamplerMinMagFilterLinear,
|
||||||
|
_ => Metal::MTLSamplerMipFilterNearest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FilterMode {
|
||||||
|
/// Get the mipmap filtering mode for the given combination.
|
||||||
|
pub fn mtl_mip(&self, mip: FilterMode) -> Metal::MTLSamplerMipFilter {
|
||||||
|
match self {
|
||||||
|
FilterMode::Linear => Metal::MTLSamplerMipFilterLinear,
|
||||||
|
FilterMode::Nearest => Metal::MTLSamplerMipFilterNearest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
30
librashader-runtime-metal/Cargo.toml
Normal file
30
librashader-runtime-metal/Cargo.toml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
[package]
|
||||||
|
name = "librashader-runtime-metal"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
license = "MPL-2.0 OR GPL-3.0-only"
|
||||||
|
version = "0.2.0-beta.7"
|
||||||
|
authors = ["Ronny Chan <ronny@ronnychan.ca>"]
|
||||||
|
repository = "https://github.com/SnowflakePowered/librashader"
|
||||||
|
readme = "../README.md"
|
||||||
|
categories = ["emulators", "compilers", "graphics"]
|
||||||
|
keywords = ["shader", "retroarch", "SPIR-V"]
|
||||||
|
description = "RetroArch shaders for all."
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
librashader-common = { path = "../librashader-common", features = ["vulkan"], version = "0.2.0-beta.7" }
|
||||||
|
librashader-presets = { path = "../librashader-presets", version = "0.2.0-beta.7" }
|
||||||
|
librashader-preprocess = { path = "../librashader-preprocess", version = "0.2.0-beta.7" }
|
||||||
|
librashader-reflect = { path = "../librashader-reflect", version = "0.2.0-beta.7" }
|
||||||
|
librashader-runtime = { path = "../librashader-runtime" , version = "0.2.0-beta.7" }
|
||||||
|
librashader-cache = { path = "../librashader-cache", version = "0.2.0-beta.7" }
|
||||||
|
|
||||||
|
icrate = { version = "0.1.0" , features = [ "Metal", "Metal_all", "MetalKit" ]}
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["librashader-cache/docsrs"]
|
1
librashader-runtime-metal/src/lib.rs
Normal file
1
librashader-runtime-metal/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
mod samplers;
|
71
librashader-runtime-metal/src/samplers.rs
Normal file
71
librashader-runtime-metal/src/samplers.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
use icrate::Metal::{MTLDevice, MTLSamplerDescriptor, MTLSamplerState};
|
||||||
|
use objc2::rc::Id;
|
||||||
|
use objc2::runtime::ProtocolObject;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use librashader_common::{FilterMode, WrapMode};
|
||||||
|
|
||||||
|
pub struct SamplerSet {
|
||||||
|
// todo: may need to deal with differences in mip filter.
|
||||||
|
samplers: FxHashMap<(WrapMode, FilterMode, FilterMode), Id<ProtocolObject<dyn MTLSamplerState>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SamplerSet {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get(&self, wrap: WrapMode, filter: FilterMode, mipmap: FilterMode) -> Id<ProtocolObject<dyn MTLSamplerState>>> {
|
||||||
|
// eprintln!("{wrap}, {filter}, {mip}");
|
||||||
|
// SAFETY: the sampler set is complete for the matrix
|
||||||
|
// wrap x filter x mipmap
|
||||||
|
unsafe {
|
||||||
|
Id::clone(
|
||||||
|
&self
|
||||||
|
.samplers
|
||||||
|
.get(&(wrap, filter, mipmap))
|
||||||
|
.unwrap_unchecked(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(device: &dyn MTLDevice) -> SamplerSet {
|
||||||
|
let mut samplers = FxHashMap::default();
|
||||||
|
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(MTLSamplerA)
|
||||||
|
samplers.insert(
|
||||||
|
(*wrap_mode, *filter_mode, *mipmap_filter),
|
||||||
|
|
||||||
|
device.newSamplerStateWithDescriptor(&MTLSamplerDescriptor {
|
||||||
|
|
||||||
|
})
|
||||||
|
Arc::new(device.create_sampler(&SamplerDescriptor {
|
||||||
|
label: None,
|
||||||
|
address_mode_u: (*wrap_mode).into(),
|
||||||
|
address_mode_v: (*wrap_mode).into(),
|
||||||
|
address_mode_w: (*wrap_mode).into(),
|
||||||
|
mag_filter: (*filter_mode).into(),
|
||||||
|
min_filter: (*filter_mode).into(),
|
||||||
|
mipmap_filter: (*mipmap_filter).into(),
|
||||||
|
lod_min_clamp: 0.0,
|
||||||
|
lod_max_clamp: 1000.0,
|
||||||
|
compare: None,
|
||||||
|
anisotropy_clamp: 1,
|
||||||
|
border_color: Some(SamplerBorderColor::TransparentBlack),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert all samplers were created.
|
||||||
|
assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2);
|
||||||
|
SamplerSet { samplers }
|
||||||
|
}
|
||||||
|
}
|
84
librashader-runtime-mtl/src/samplers.rs
Normal file
84
librashader-runtime-mtl/src/samplers.rs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
use icrate::Metal::{
|
||||||
|
MTLCompareFunctionNever, MTLDevice, MTLSamplerAddressMode,
|
||||||
|
MTLSamplerBorderColorTransparentBlack, MTLSamplerDescriptor, MTLSamplerMinMagFilter,
|
||||||
|
MTLSamplerState,
|
||||||
|
};
|
||||||
|
use librashader_common::{FilterMode, WrapMode};
|
||||||
|
use objc2::rc::Id;
|
||||||
|
use objc2::runtime::ProtocolObject;
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
|
use crate::error::{FilterChainError, Result};
|
||||||
|
|
||||||
|
pub struct SamplerSet {
|
||||||
|
// todo: may need to deal with differences in mip filter.
|
||||||
|
samplers:
|
||||||
|
FxHashMap<(WrapMode, FilterMode, FilterMode), Id<ProtocolObject<dyn MTLSamplerState>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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: &Id<ProtocolObject<dyn MTLSamplerState>> = unsafe {
|
||||||
|
self.samplers
|
||||||
|
.get(&(wrap, filter, mipmap))
|
||||||
|
.unwrap_unchecked()
|
||||||
|
};
|
||||||
|
|
||||||
|
id.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(device: &ProtocolObject<dyn MTLDevice>) -> Result<SamplerSet> {
|
||||||
|
let mut samplers = FxHashMap::default();
|
||||||
|
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(MTLCompareFunctionNever);
|
||||||
|
descriptor.setMaxAnisotropy(1);
|
||||||
|
descriptor.setBorderColor(MTLSamplerBorderColorTransparentBlack);
|
||||||
|
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 })
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue