Safe Rust bindings for Apple's
MetalPerformanceShaders
framework on macOS.
The GitHub repository is mps-rs; the published crates.io package is
apple-mps because the mps-rs package name is already taken.
[dependencies]
apple-mps = "0.3"
apple-metal = "0.10"Requires macOS 11 or later and Rust 1.82. Buffer-backed NDArrays and
NDArrayIdentity need macOS 15 and report Error::Unsupported or None on
older systems. The ray-tracing types wrap APIs Apple deprecated in macOS 14.
use apple_metal::MetalDevice;
use apple_mps::{feature_channel_format, Image, ImageDescriptor, ImageGaussianBlur};
let device = MetalDevice::system_default().expect("no Metal device");
let queue = device.new_command_queue().expect("queue");
let descriptor = ImageDescriptor::new(256, 256, 1, feature_channel_format::FLOAT32);
let src = Image::new(&device, descriptor).expect("source image");
let dst = Image::new(&device, descriptor).expect("destination image");
let blur = ImageGaussianBlur::new(&device, 2.0).expect("gaussian blur");
let command_buffer = queue.new_command_buffer().expect("command buffer");
blur.encode_image(&command_buffer, &src, &dst).expect("encode blur");- Only part of the umbrella is usable: most kernel classes are opaque handles without
constructors or encode methods.
COVERAGE.mdlists what is wrapped. - Core helpers:
supports_mtl_device,preferred_device,hint_temporary_memory_high_water_mark,set_heap_cache_durationPredicateandMpsCommandBuffer(predicates and heap prefetch only; the encoders takeapple_metal::CommandBuffer, so kernels never see anMpsCommandBufferpredicate).MpsCommandBuffer::command_bufferreturns the wrapped apple-metal command buffer, which is how a buffer made byfrom_command_queueis committed
- Images:
ImageDescriptor+Imagefor lazily allocated MPS images or texture-backed images- Float32 image read/write helpers plus raw byte transfers with
MPSDataLayout, checked against the image's channel format, region and feature-channel window - Unary image filters:
ImageGaussianBlurImageBoxImageSobelImageMedianImageConvolutionImageBilinearScaleImageLanczosScaleImageThresholdBinaryImageStatisticsMinAndMaxImageStatisticsMeanImageReduceRowMin,ImageReduceRowMax,ImageReduceRowMean,ImageReduceRowSum
ImageHistogram,ImageAdd, andImageScaleAndAdd
- Matrix/vector:
MatrixDescriptor,VectorDescriptor,MatrixMultiplicationDescriptor,Matrix,Vector, andMatrixMultiplication
NDArray:NDArrayDescriptor,NDArray,NDArrayIdentity, andNDArrayMatrixMultiplication
- State:
State,StateResourceList,StateTextureInfostate_batch_increment_read_count,state_batch_resource_size,state_batch_synchronize
- Ray tracing / denoising:
PolygonAccelerationStructure,RayIntersector, andSVGF
- Neural / optimizer / RNN:
NNImageNode,NNGraphCnnNeuronReluNode,CnnPoolingMaxNode,CnnSoftMaxNode,CnnUpsamplingNearestNodeCnnConvolutionDescriptor,CnnConvolution,CnnConvolutionWeightsAndBiasesStateNNOptimizerDescriptor,NNOptimizer,NNOptimizerStochasticGradientDescent,NNOptimizerRmsProp,NNOptimizerAdamRnnDescriptor,RnnSingleGateDescriptor,GruDescriptor,LstmDescriptor,RnnImageInferenceLayer,RnnRecurrentImageState
- Shared constants for
MPSKernelOptions,MPSImageEdgeMode,MPSImageFeatureChannelFormat,MPSDataType,MPSDataLayout, plus convolution / optimizer / RNN / state enums
See COVERAGE.md for the family matrix and what the coverage audit measures.
- Constructors and encode methods check buffer lengths, strides, offsets, shapes and data
types before calling MPS and return
Err(orNone) instead of letting MPS read or write out of bounds or abort the process. - Image filters check their textures against each kernel's rules before encoding (pixel
format class, color model or channel count, texture type, feature channels, aliasing,
shader usage, device and, for min/max statistics, destination width) and return
Err. - Every encode runs through apple-metal's
CommandBuffer::encode_foreign. It returnsError::CommandBufferwhen the command buffer no longer records (InvalidState) or an apple-metal encoder is still open on it (ActiveEncoder), where MPS would abort the process. While MPS encodes, commits, enqueues and new encoders on the same command buffer fail withActiveEncoderon every thread, so a concurrent commit can't land mid-encode. - Temporary
States follow MPS's read-count rules. Dropping one returns its storage (read count 0).set_read_countrefuses persistent states and raising a count that reached zero,state_batch_increment_read_countrefuses to take a count below zero and leaves persistent states unchanged, and temporary states cannot be synchronized with the CPU. Read-count changes, including the zeroing on drop, go through the command buffer's encode guard: while another encoder is open on it they returnActiveEncoder, and a temporary state dropped then is leaked. The crate hands out no other temporary objects: NDArray kernel results are regular arrays, temporary RNN recurrent outputs are refused, andNNGraph::encodereleases the temporary images it exports from intermediate nodes. The test suite runs clean under the Metal validation layer (MTL_DEBUG_LAYER=1). - MPS kernels and descriptors are
Sendbut notSync: MPS allows a kernel to be used by one thread at a time. Data objects such asMatrix,Vector,NDArrayandImageremainSync. PolygonAccelerationStructure::set_index_bufferisunsafe: every index read for the configured polygons must be smaller than the number of vertices in the vertex buffer whenever the structure is rebuilt, refit or used, because MPS reads vertices through the indices without checking them.- As Apple documents, GPU writes to geometry, ray and image data must have completed
before
rebuildor a CPU image transfer reads it.
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
MTL_DEBUG_LAYER=1 cargo test --all-features
cargo run --example 01_blur_image
cargo run --example 02_matrix_multiply
cargo run --example 03_ndarray_identity
cargo run --example 04_ray_intersection
cargo run --example 05_nn_graph_relu
cargo run --example 06_ndarray_matrix_multiplication
cargo run --example 07_optimizer_and_state
cargo run --example 08_cnn_convolution
cargo run --example 09_rnn_image_inference