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

Added support for IO commands #306

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
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
Loading