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

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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 --all-targets --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.28.0", git = "https://github.com/gfx-rs/metal-rs", rev = "0d6214f", default-features = false, features = ["link", "dispatch"], optional = true }
[target.'cfg(target_vendor = "apple")'.dependencies]
objc2 = { version = "0.5", default-features = false, optional = true }
objc2-foundation = { version = "0.2", default-features = false, optional = true }
objc2-metal = { version = "0.2.2", 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 @@ -64,6 +74,11 @@ features = [
"Win32_Graphics_Dxgi_Common",
]

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

[[example]]
name = "vulkan-buffer"
required-features = ["vulkan", "ash/loaded"]
Expand All @@ -84,8 +99,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
40 changes: 22 additions & 18 deletions examples/d3d12-buffer-winrs.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
//! Example showcasing [`gpu-allocator`] with types and functions from the [`windows`] crate.
use gpu_allocator::d3d12::{
AllocationCreateDesc, Allocator, AllocatorCreateDesc, ID3D12DeviceVersion, ResourceCategory,
use gpu_allocator::{
d3d12::{
AllocationCreateDesc, Allocator, AllocatorCreateDesc, ID3D12DeviceVersion, ResourceCategory,
},
MemoryLocation,
};
use gpu_allocator::MemoryLocation;
use log::*;
use windows::core::{Interface, Result};
use windows::Win32::{
Foundation::E_NOINTERFACE,
Graphics::{
Direct3D::{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_12_0},
Direct3D12::{
D3D12CreateDevice, ID3D12Device, ID3D12Resource,
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, D3D12_RESOURCE_DESC,
D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COMMON,
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
},
Dxgi::{
Common::{DXGI_FORMAT_UNKNOWN, DXGI_SAMPLE_DESC},
CreateDXGIFactory2, IDXGIAdapter4, IDXGIFactory6, DXGI_ADAPTER_FLAG3_SOFTWARE,
DXGI_ERROR_NOT_FOUND,
use windows::{
core::{Interface, Result},
Win32::{
Foundation::E_NOINTERFACE,
Graphics::{
Direct3D::{D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_12_0},
Direct3D12::{
D3D12CreateDevice, ID3D12Device, ID3D12Resource,
D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT, D3D12_RESOURCE_DESC,
D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_FLAG_NONE,
D3D12_RESOURCE_STATE_COMMON, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
},
Dxgi::{
Common::{DXGI_FORMAT_UNKNOWN, DXGI_SAMPLE_DESC},
CreateDXGIFactory2, IDXGIAdapter4, IDXGIFactory6, DXGI_ADAPTER_FLAG3_SOFTWARE,
DXGI_ERROR_NOT_FOUND,
},
},
},
};
Expand Down
21 changes: 12 additions & 9 deletions examples/d3d12-buffer.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
//! Example showcasing [`winapi`] interop with [`gpu-allocator`] which is driven by the [`windows`] crate.
use winapi::shared::{dxgiformat, winerror};
use winapi::um::{d3d12, d3dcommon};
use winapi::Interface;
use winapi::{
shared::{dxgiformat, winerror},
um::{d3d12, d3dcommon},
Interface,
};

mod all_dxgi {
pub use winapi::shared::{dxgi1_3::*, dxgi1_6::*, dxgitype::*};
}

use log::*;

use gpu_allocator::d3d12::{
AllocationCreateDesc, Allocator, AllocatorCreateDesc, ID3D12DeviceVersion, ResourceCategory,
ToWinapi, ToWindows,
use gpu_allocator::{
d3d12::{
AllocationCreateDesc, Allocator, AllocatorCreateDesc, ID3D12DeviceVersion,
ResourceCategory, ToWinapi, ToWindows,
},
MemoryLocation,
};
use gpu_allocator::MemoryLocation;
use log::*;

fn create_d3d12_device(
dxgi_factory: *mut all_dxgi::IDXGIFactory6,
Expand Down
30 changes: 17 additions & 13 deletions examples/metal-buffer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
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());
let device = unsafe { metal::MTLCreateSystemDefaultDevice() };
// TODO: Not SendSync
let device = unsafe { Id::from_raw(device) }.expect("No MTLDevice found");

// Setting up the allocator
let mut allocator = Allocator::new(&AllocatorCreateDesc {
Expand Down Expand Up @@ -60,11 +64,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 +79,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
9 changes: 4 additions & 5 deletions examples/vulkan-buffer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::default::Default;

use ash::vk;
use log::info;

use gpu_allocator::vulkan::{
AllocationCreateDesc, AllocationScheme, Allocator, AllocatorCreateDesc,
use gpu_allocator::{
vulkan::{AllocationCreateDesc, AllocationScheme, Allocator, AllocatorCreateDesc},
MemoryLocation,
};
use gpu_allocator::MemoryLocation;
use log::info;

fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init();
Expand Down
18 changes: 8 additions & 10 deletions src/d3d12/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)]

use std::{backtrace::Backtrace, fmt, sync::Arc};

use log::{debug, warn, Level};

use windows::Win32::{
Foundation::E_OUTOFMEMORY,
Graphics::{Direct3D12::*, Dxgi::Common::DXGI_FORMAT},
};

#[cfg(feature = "public-winapi")]
mod public_winapi {
use super::*;
pub use winapi::um::d3d12 as winapi_d3d12;

use super::*;

/// Trait similar to [`AsRef`]/[`AsMut`],
pub trait ToWinapi<T> {
fn as_winapi(&self) -> *const T;
Expand Down Expand Up @@ -84,9 +82,7 @@ mod visualizer;
#[cfg(feature = "visualizer")]
pub use visualizer::AllocatorVisualizer;

use super::allocator;
use super::allocator::AllocationType;

use super::{allocator, allocator::AllocationType};
use crate::{
allocator::{AllocatorReport, MemoryBlockReport},
AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, Result,
Expand Down Expand Up @@ -197,10 +193,12 @@ impl<'a> AllocationCreateDesc<'a> {
desc: &winapi_d3d12::D3D12_RESOURCE_DESC,
name: &'a str,
location: MemoryLocation,
) -> AllocationCreateDesc<'a> {
) -> Self {
let device = device.as_windows();
// Raw structs are binary-compatible
let desc = unsafe { std::mem::transmute(desc) };
let desc = unsafe {
std::mem::transmute::<&winapi_d3d12::D3D12_RESOURCE_DESC, &D3D12_RESOURCE_DESC>(desc)
};
let allocation_info =
unsafe { device.GetResourceAllocationInfo(0, std::slice::from_ref(desc)) };
let resource_category: ResourceCategory = desc.into();
Expand All @@ -223,7 +221,7 @@ impl<'a> AllocationCreateDesc<'a> {
desc: &D3D12_RESOURCE_DESC,
name: &'a str,
location: MemoryLocation,
) -> AllocationCreateDesc<'a> {
) -> Self {
let allocation_info =
unsafe { device.GetResourceAllocationInfo(0, std::slice::from_ref(desc)) };
let resource_category: ResourceCategory = desc.into();
Expand Down
4 changes: 2 additions & 2 deletions src/d3d12/visualizer.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#![allow(clippy::new_without_default)]

use windows::Win32::Graphics::Direct3D12::*;

use super::Allocator;
use crate::visualizer::{
render_allocation_reports_ui, AllocationReportVisualizeSettings, ColorScheme,
MemoryChunksVisualizationSettings,
};

use windows::Win32::Graphics::Direct3D12::*;

struct AllocatorVisualizerBlockWindow {
memory_type_index: usize,
block_index: usize,
Expand Down
18 changes: 11 additions & 7 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,10 +180,12 @@
//! ```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(),
Expand All @@ -194,7 +197,7 @@
//! &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 +209,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 +227,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
Loading