Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🤘 metal: Migrate to objc2 architecture with objc2-metal bindings #225

Merged
merged 3 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,6 @@ jobs:
uses: dtolnay/rust-toolchain@nightly
- name: Generate lockfile with minimal dependency versions
run: cargo +nightly generate-lockfile -Zminimal-versions
- name: Bump `libc 0.1` version to `0.2` via `malloc_buf 0.0.6`
if: ${{ runner.os == 'macOS' }}
run: |
# The 7-year-unmaintained malloc_buf (depended on via metal-rs->objc)
# only allows using libc 0.2 since the 0.0.6 release, which is necessary
# since the libc 0.1 range no longer compiles. Fortunately objc which
# is also unmaintained for 4 years depends on malloc_buf >=0.0,<0.1.0,
# allowing the 0.0.6 release to be used (but not the 1.0.0 release).
cargo update -p malloc_buf --precise 0.0.6
- name: Cargo clippy with minimal-versions
run: cargo +stable clippy --workspace --features ${{ matrix.features }} --no-default-features -- -D warnings

Expand Down
23 changes: 19 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,18 @@ ash = { version = "0.38", optional = true, default-features = false, features =
egui = { version = ">=0.24, <=0.27", optional = true, default-features = false }
egui_extras = { version = ">=0.24, <=0.27", optional = true, default-features = false }

[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
metal = { version = "0.29.0", default-features = false, features = ["link", "dispatch"], optional = true }
[target.'cfg(target_vendor = "apple")'.dependencies]
objc2 = { version = "0.5.2", default-features = false, optional = true }
objc2-foundation = { version = "0.2", default-features = false, optional = true }
objc2-metal = { version = "0.2.1", default-features = false, features = [
"MTLAccelerationStructure",
"MTLBuffer",
"MTLDevice",
"MTLHeap",
"MTLResource",
"MTLTexture",
"std",
], optional = true }

[target.'cfg(windows)'.dependencies]
# Only needed for public-winapi interop helpers
Expand Down Expand Up @@ -65,6 +75,11 @@ features = [
"Win32_Graphics_Dxgi_Common",
]

[target.'cfg(target_vendor = "apple")'.dev-dependencies]
objc2-metal = { version = "0.2.1", default-features = false, features = [
"MTLPixelFormat",
] }

[[example]]
name = "vulkan-buffer"
required-features = ["vulkan", "ash/loaded"]
Expand All @@ -85,8 +100,8 @@ required-features = ["metal"]
visualizer = ["dep:egui", "dep:egui_extras"]
vulkan = ["dep:ash"]
d3d12 = ["dep:windows"]
metal = ["dep:metal"]
metal = ["dep:objc2", "dep:objc2-metal", "dep:objc2-foundation"]
# Expose helper functionality for winapi types to interface with gpu-allocator, which is primarily windows-rs driven
public-winapi = ["dep:winapi"]

default = ["d3d12", "vulkan"]
default = ["d3d12", "vulkan", "metal"]
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ allocator.free(allocation).unwrap();

```rust
use gpu_allocator::metal::*;

use objc2_metal as metal;
let mut allocator = Allocator::new(&AllocatorCreateDesc {
device: device.clone(),
debug_settings: Default::default(),
Expand All @@ -146,12 +146,12 @@ let mut allocator = Allocator::new(&AllocatorCreateDesc {
```rust
use gpu_allocator::metal::*;
use gpu_allocator::MemoryLocation;

use objc2_metal as metal;
let allocation_desc = AllocationCreateDesc::buffer(
&device,
"Example allocation",
512, // size in bytes
gpu_allocator::MemoryLocation::GpuOnly,
MemoryLocation::GpuOnly,
);
let allocation = allocator.allocate(&allocation_desc).unwrap();
let resource = allocation.make_buffer().unwrap();
Expand Down
34 changes: 21 additions & 13 deletions examples/metal-buffer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
use std::sync::Arc;

use gpu_allocator::metal::{AllocationCreateDesc, Allocator, AllocatorCreateDesc};
use log::info;
use metal::MTLDevice as _;
use objc2::rc::Id;
use objc2_foundation::NSArray;
use objc2_metal as metal;

fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init();

let device = Arc::new(metal::Device::system_default().unwrap());
// Allow the innards of objc2-metal to link the static function below:
// https://docs.rs/objc2-metal/0.2.2/objc2_metal/index.html
#[link(name = "CoreGraphics", kind = "framework")]
extern "C" {}

let device =
unsafe { Id::from_raw(metal::MTLCreateSystemDefaultDevice()) }.expect("No MTLDevice found");

// Setting up the allocator
let mut allocator = Allocator::new(&AllocatorCreateDesc {
Expand Down Expand Up @@ -60,11 +68,11 @@ fn main() {

// Test allocating texture
{
let texture_desc = metal::TextureDescriptor::new();
texture_desc.set_pixel_format(metal::MTLPixelFormat::RGBA8Unorm);
texture_desc.set_width(64);
texture_desc.set_height(64);
texture_desc.set_storage_mode(metal::MTLStorageMode::Private);
let texture_desc = unsafe { metal::MTLTextureDescriptor::new() };
texture_desc.setPixelFormat(metal::MTLPixelFormat::RGBA8Unorm);
unsafe { texture_desc.setWidth(64) };
unsafe { texture_desc.setHeight(64) };
texture_desc.setStorageMode(metal::MTLStorageMode::Private);
let allocation_desc =
AllocationCreateDesc::texture(&device, "Test allocation (Texture)", &texture_desc);
let allocation = allocator.allocate(&allocation_desc).unwrap();
Expand All @@ -75,14 +83,14 @@ fn main() {

// Test allocating acceleration structure
{
let empty_array = metal::Array::from_slice(&[]);
let acc_desc = metal::PrimitiveAccelerationStructureDescriptor::descriptor();
acc_desc.set_geometry_descriptors(empty_array);
let sizes = device.acceleration_structure_sizes_with_descriptor(&acc_desc);
let empty_array = NSArray::from_slice(&[]);
let acc_desc = metal::MTLPrimitiveAccelerationStructureDescriptor::descriptor();
acc_desc.setGeometryDescriptors(Some(&empty_array));
let sizes = device.accelerationStructureSizesWithDescriptor(&acc_desc);
let allocation_desc = AllocationCreateDesc::acceleration_structure_with_size(
&device,
"Test allocation (Acceleration structure)",
sizes.acceleration_structure_size,
sizes.accelerationStructureSize as u64,
gpu_allocator::MemoryLocation::GpuOnly,
);
let allocation = allocator.allocate(&allocation_desc).unwrap();
Expand Down
10 changes: 8 additions & 2 deletions src/d3d12/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use std::{backtrace::Backtrace, fmt, sync::Arc};
use std::{
backtrace::Backtrace,
fmt,
// TODO: Remove when bumping MSRV to 1.80
mem::size_of_val,
sync::Arc,
};

use log::{debug, warn, Level};
use windows::Win32::{
Expand Down Expand Up @@ -628,7 +634,7 @@ impl Allocator {
device.CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS,
<*mut D3D12_FEATURE_DATA_D3D12_OPTIONS>::cast(&mut options),
std::mem::size_of_val(&options) as u32,
size_of_val(&options) as u32,
)
}
.map_err(|e| {
Expand Down
19 changes: 11 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,11 @@
//! ```no_run
//! # #[cfg(feature = "metal")]
//! # fn main() {
//! # use std::sync::Arc;
//! use gpu_allocator::metal::*;
//!
//! # let device = Arc::new(metal::Device::system_default().unwrap());
//! # use objc2::rc::Id;
//! use objc2_metal as metal;
//! # let device = unsafe { metal::MTLCreateSystemDefaultDevice() };
//! # let device = unsafe { Id::from_raw(device) }.expect("No MTLDevice found");
//! let mut allocator = Allocator::new(&AllocatorCreateDesc {
//! device: device.clone(),
//! debug_settings: Default::default(),
Expand All @@ -179,22 +180,23 @@
//! ```no_run
//! # #[cfg(feature = "metal")]
//! # fn main() {
//! # use std::sync::Arc;
//! use gpu_allocator::metal::*;
//! use gpu_allocator::MemoryLocation;
//! # let device = Arc::new(metal::Device::system_default().unwrap());
//! # use objc2::rc::Id;
//! use objc2_metal as metal;
//! # let device = unsafe { metal::MTLCreateSystemDefaultDevice() };
//! # let device = unsafe { Id::from_raw(device) }.expect("No MTLDevice found");
//! # let mut allocator = Allocator::new(&AllocatorCreateDesc {
//! # device: device.clone(),
//! # debug_settings: Default::default(),
//! # allocation_sizes: Default::default(),
//! # })
//! # .unwrap();
//!
//! let allocation_desc = AllocationCreateDesc::buffer(
//! &device,
//! "Example allocation",
//! 512, // size in bytes
//! gpu_allocator::MemoryLocation::GpuOnly,
//! MemoryLocation::GpuOnly,
//! );
//! let allocation = allocator.allocate(&allocation_desc).unwrap();
//! let resource = allocation.make_buffer().unwrap();
Expand All @@ -206,6 +208,7 @@
//! # #[cfg(not(feature = "metal"))]
//! # fn main() {}
//! ```
#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)]

mod result;
pub use result::*;
Expand All @@ -223,7 +226,7 @@ pub mod vulkan;
#[cfg(all(windows, feature = "d3d12"))]
pub mod d3d12;

#[cfg(all(any(target_os = "macos", target_os = "ios"), feature = "metal"))]
#[cfg(all(target_vendor = "apple", feature = "metal"))]
pub mod metal;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
Expand Down
Loading