Skip to content

Commit

Permalink
Added support for IO commands
Browse files Browse the repository at this point in the history
  • Loading branch information
zmarlon committed Apr 19, 2024
1 parent ff8fd3d commit cbb8368
Show file tree
Hide file tree
Showing 7 changed files with 495 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/io-command-queue/content.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HelloThisIsATest
31 changes: 31 additions & 0 deletions examples/io-command-queue/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use metal::{Device, IOCommandQueueDescriptor, MTLIOPriority, MTLResourceOptions, URL};
use std::{fs, slice};

fn main() {
let device = Device::system_default().unwrap();

let descriptor = IOCommandQueueDescriptor::new();
descriptor.set_priority(MTLIOPriority::High);

let io_queue = device.new_io_command_queue(&descriptor).unwrap();

let path = "examples/io-command-queue/content.txt";

let len = fs::metadata(path).unwrap().len();
let buffer = device.new_buffer(len, MTLResourceOptions::empty());

let handle = device
.new_io_file_handle(&URL::new_with_path(path))
.unwrap();

let io_command_buffer = io_queue.new_command_buffer();
io_command_buffer.load_buffer(&buffer, 0, len, &handle, 0);
io_command_buffer.commit();
io_command_buffer.wait_until_completed();

let content = unsafe {
std::str::from_utf8_unchecked(slice::from_raw_parts(buffer.contents().cast(), len as _))
};

println!("{content}");
}
73 changes: 73 additions & 0 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use super::*;
use block::{Block, ConcreteBlock};
use objc::runtime::{NO, YES};

use crate::iocommandqueue::{IOCommandQueue, IOCommandQueueDescriptorRef, MTLIOCommandQueue};
use std::{ffi::CStr, os::raw::c_char, path::Path, ptr};

/// Available on macOS 10.11+, iOS 8.0+, tvOS 9.0+
Expand Down Expand Up @@ -1660,6 +1661,78 @@ impl DeviceRef {
unsafe { msg_send![self, newCommandQueueWithMaxCommandBufferCount: count] }
}

pub fn new_io_command_queue(
&self,
descriptor: &IOCommandQueueDescriptorRef,
) -> Result<IOCommandQueue, String> {
unsafe {
let mut err: *mut Object = ptr::null_mut();
let queue: *mut MTLIOCommandQueue = msg_send![self, newIOCommandQueueWithDescriptor:descriptor
error:&mut err];

if !err.is_null() {
let desc: *mut Object = msg_send![err, localizedDescription];
let error: *const c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(error).to_string_lossy().into_owned();
if queue.is_null() {
return Err(message);
} else {
warn!("Warning: {}", message);
}
}

assert!(!queue.is_null());
Ok(IOCommandQueue::from_ptr(queue))
}
}

pub fn new_io_file_handle(&self, url: &URLRef) -> Result<IOFileHandle, String> {
unsafe {
let mut err: *mut Object = ptr::null_mut();
let handle: *mut MTLIOFileHandle =
msg_send![self, newIOFileHandleWithURL:url error:&mut err];

if !err.is_null() {
let desc: *mut Object = msg_send![err, localizedDescription];
let error: *const c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(error).to_string_lossy().into_owned();
if handle.is_null() {
return Err(message);
} else {
warn!("Warning: {}", message);
}
}

assert!(!handle.is_null());
Ok(IOFileHandle::from_ptr(handle))
}
}

pub fn new_io_file_handle_with_compression(
&self,
url: &URLRef,
compression_method: MTLIOCompressionMethod,
) -> Result<IOFileHandle, String> {
unsafe {
let mut err: *mut Object = ptr::null_mut();
let handle: *mut MTLIOFileHandle = msg_send![self, newIOFileHandleWithURL:url compressionMethod: compression_method error:&mut err];

if !err.is_null() {
let desc: *mut Object = msg_send![err, localizedDescription];
let error: *const c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(error).to_string_lossy().into_owned();
if handle.is_null() {
return Err(message);
} else {
warn!("Warning: {}", message);
}
}

assert!(!handle.is_null());
Ok(IOFileHandle::from_ptr(handle))
}
}

pub fn new_default_library(&self) -> Library {
unsafe { msg_send![self, newDefaultLibrary] }
}
Expand Down
149 changes: 149 additions & 0 deletions src/iocommandbuffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2016 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use super::*;

use crate::{
BufferRef, IOFileHandleRef, MTLOrigin, MTLSize, NSUInteger, SharedEventRef, TextureRef,
};
use block::Block;
use objc::runtime::Object;
use std::ffi::c_void;

type IOCommandBufferHandler<'a> = Block<(&'a IOCommandBufferRef,), ()>;

/// See <https://developer.apple.com/documentation/metal/mtliostatus>
#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum MTLIOStatus {
Pending = 0,
Complete = 3,
Cancelled = 1,
Error = 2,
}

/// See <https://developer.apple.com/documentation/metal/mtliocommandbuffer>.
pub enum MTLIOCommandBuffer {}

foreign_obj_type! {
type CType = MTLIOCommandBuffer;
pub struct IOCommandBuffer;
}

impl IOCommandBufferRef {
pub fn load_buffer(
&self,
buffer: &BufferRef,
offset: NSUInteger,
size: NSUInteger,
source_handle: &IOFileHandleRef,
source_handle_offset: NSUInteger,
) {
unsafe {
msg_send![self, loadBuffer: buffer offset: offset size: size sourceHandle: source_handle sourceHandleOffset: source_handle_offset]
}
}

pub fn load_texture(
&self,
texture: &TextureRef,
slice: NSUInteger,
level: NSUInteger,
size: MTLSize,
source_bytes_per_row: NSUInteger,
source_bytes_per_image: NSUInteger,
destination_origin: MTLOrigin,
source_handle: &IOFileHandleRef,
source_handle_offset: NSUInteger,
) {
unsafe {
msg_send![self, loadTexture: texture slice: slice level: level size: size sourceBytesPerRow: source_bytes_per_row sourceBytesPerImage: source_bytes_per_image destinationOrigin: destination_origin sourceHandle: source_handle sourceHandleOffset: source_handle_offset]
}
}

pub fn load_bytes(
&self,
pointer: *mut c_void,
size: NSUInteger,
source_handle: &IOFileHandleRef,
source_handle_offset: NSUInteger,
) {
unsafe {
msg_send![self, loadBytes: pointer size: size sourceHandle: source_handle sourceHandleOffset: source_handle_offset]
}
}

pub fn add_barrier(&self) {
unsafe { msg_send![self, addBarrier] }
}

pub fn signal_event(&self, event: &SharedEventRef, value: u64) {
unsafe { msg_send![self, signalEvent: event value: value] }
}

pub fn wait_for_event(&self, event: &SharedEventRef, value: u64) {
unsafe { msg_send![self, waitForEvent: event value: value] }
}

pub fn copy_status_to_buffer(&self, buffer: &BufferRef, offset: NSUInteger) {
unsafe { msg_send![self, copyStatusToBuffer: buffer offset: offset] }
}

pub fn add_completion_handler(&self, block: &IOCommandBufferHandler) {
unsafe { msg_send![self, addCompletedHandler: block] }
}

pub fn commit(&self) {
unsafe { msg_send![self, commit] }
}

pub fn enqueue(&self) {
unsafe { msg_send![self, enqueue] }
}

pub fn try_cancel(&self) {
unsafe { msg_send![self, tryCancel] }
}

pub fn wait_until_completed(&self) {
unsafe { msg_send![self, waitUntilCompleted] }
}

pub fn status(&self) -> MTLIOStatus {
unsafe { msg_send![self, status] }
}

pub fn error(&self) -> *mut Object {
unsafe { msg_send![self, error] }
}

pub fn label(&self) -> &str {
unsafe {
let label = msg_send![self, label];
crate::nsstring_as_str(label)
}
}

pub fn set_label(&self, label: &str) {
unsafe {
let nslabel = crate::nsstring_from_str(label);
msg_send![self, setLabel: nslabel]
}
}

pub fn push_debug_group(&self, string: &str) {
unsafe {
let nsstring = crate::nsstring_from_str(string);
msg_send![self, pushDebugGroup: nsstring]
}
}

pub fn pop_debug_group(&self) {
unsafe { msg_send![self, popDebugGroup] }
}
}
Loading

0 comments on commit cbb8368

Please sign in to comment.