diff --git a/examples/io-command-queue/content.txt b/examples/io-command-queue/content.txt new file mode 100644 index 0000000..572b057 --- /dev/null +++ b/examples/io-command-queue/content.txt @@ -0,0 +1 @@ +HelloThisIsATest \ No newline at end of file diff --git a/examples/io-command-queue/main.rs b/examples/io-command-queue/main.rs new file mode 100644 index 0000000..463dadb --- /dev/null +++ b/examples/io-command-queue/main.rs @@ -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}"); +} diff --git a/src/device.rs b/src/device.rs index 75061cc..c339af9 100644 --- a/src/device.rs +++ b/src/device.rs @@ -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+ @@ -1660,6 +1661,78 @@ impl DeviceRef { unsafe { msg_send![self, newCommandQueueWithMaxCommandBufferCount: count] } } + pub fn new_io_command_queue( + &self, + descriptor: &IOCommandQueueDescriptorRef, + ) -> Result { + 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 { + 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 { + 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] } } diff --git a/src/iocommandbuffer.rs b/src/iocommandbuffer.rs new file mode 100644 index 0000000..5249d46 --- /dev/null +++ b/src/iocommandbuffer.rs @@ -0,0 +1,149 @@ +// Copyright 2016 GFX developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , 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 +#[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 . +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] } + } +} diff --git a/src/iocommandqueue.rs b/src/iocommandqueue.rs new file mode 100644 index 0000000..a564f7d --- /dev/null +++ b/src/iocommandqueue.rs @@ -0,0 +1,195 @@ +// Copyright 2016 GFX developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use super::*; + +/// See +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLIOCompressionMethod { + Zlib = 0, + LZFSE = 1, + LZ4 = 2, + LZMA = 3, + LZBitmap = 4, +} + +/// See . +pub enum MTLIOCommandQueue {} + +foreign_obj_type! { + type CType = MTLIOCommandQueue; + pub struct IOCommandQueue; +} + +impl IOCommandQueueRef { + pub fn new_command_buffer(&self) -> IOCommandBuffer { + unsafe { msg_send![self, commandBuffer] } + } + + pub fn new_command_buffer_with_unretained_references(&self) -> IOCommandBuffer { + unsafe { msg_send![self, commandBufferWithUnretainedReferences] } + } + + pub fn enqueue_barrier(&self) { + unsafe { + let () = msg_send![self, enqueueBarrirer]; + } + } + + 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] + } + } +} + +/// See +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLIOPriority { + Normal = 1, + Low = 2, + High = 0, +} + +/// See +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLIOCommandQueueType { + Concurrent = 0, + Serial = 1, +} + +/// See . +pub enum MTLIOScratchBuffer {} + +foreign_obj_type! { + type CType = MTLIOScratchBuffer; + pub struct IOScratchBuffer; +} + +impl IOScratchBufferRef { + pub fn buffer(&self) -> &BufferRef { + unsafe { msg_send![self, buffer] } + } +} + +/// See . +pub enum MTLIOScratchBufferAllocator {} + +foreign_obj_type! { + type CType = MTLIOScratchBufferAllocator; + pub struct IOScratchBufferAllocator; +} + +impl IOScratchBufferAllocatorRef { + pub fn new_scratch_buffer_with_minimum_size( + &self, + minimum_size: NSUInteger, + ) -> IOScratchBuffer { + unsafe { msg_send![self, newScratchBufferWithMinimumSize: minimum_size] } + } +} + +/// See +pub enum MTLIOCommandQueueDescriptor {} + +foreign_obj_type! { + type CType = MTLIOCommandQueueDescriptor; + pub struct IOCommandQueueDescriptor; +} + +impl IOCommandQueueDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLIOCommandQueueDescriptor); + msg_send![class, new] + } + } +} + +impl IOCommandQueueDescriptorRef { + pub fn set_priority(&self, priority: MTLIOPriority) { + unsafe { + msg_send![ + self, + setPriority: priority + ] + } + } + + pub fn priority(&self) -> MTLIOPriority { + unsafe { msg_send![self, priority] } + } + + pub fn set_type(&self, ty: MTLIOCommandQueueType) { + unsafe { + msg_send![ + self, + setType: ty + ] + } + } + + pub fn ty(&self) -> MTLIOPriority { + unsafe { msg_send![self, type] } + } + + pub fn set_max_commands_in_flight(&self, max_commands_in_flight: NSUInteger) { + unsafe { + msg_send![ + self, + setMaxCommandsInFlight: max_commands_in_flight + ] + } + } + + pub fn max_commands_in_flight(&self) -> NSUInteger { + unsafe { msg_send![self, maxCommandsInFlight] } + } + + pub fn set_max_command_buffers(&self, max_command_buffer: NSUInteger) { + unsafe { + msg_send![ + self, + setMaxCommandBuffers: max_command_buffer + ] + } + } + + pub fn max_command_buffer(&self) -> NSUInteger { + unsafe { msg_send![self, maxCommandBuffers] } + } + + pub fn set_scratch_buffer_allocator( + &self, + scratch_buffer_allocator: Option<&IOScratchBufferAllocatorRef>, + ) { + unsafe { + msg_send![ + self, + setScratchBufferAllocator: scratch_buffer_allocator + ] + } + } + + pub fn scratch_buffer_allocator(&self) -> Option<&IOScratchBufferAllocatorRef> { + unsafe { msg_send![self, scratchBufferAllocator] } + } +} diff --git a/src/iofilehandle.rs b/src/iofilehandle.rs new file mode 100644 index 0000000..dc6a96c --- /dev/null +++ b/src/iofilehandle.rs @@ -0,0 +1,30 @@ +// Copyright 2016 GFX developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +/// See . +pub enum MTLIOFileHandle {} + +foreign_obj_type! { + type CType = MTLIOFileHandle; + pub struct IOFileHandle; +} + +impl IOFileHandleRef { + 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] + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 535c01d..0e77715 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -557,6 +557,9 @@ mod drawable; mod encoder; mod heap; mod indirect_encoder; +mod iocommandbuffer; +mod iocommandqueue; +mod iofilehandle; mod library; #[cfg(feature = "mps")] pub mod mps; @@ -588,6 +591,9 @@ pub use { encoder::*, heap::*, indirect_encoder::*, + iocommandbuffer::*, + iocommandqueue::*, + iofilehandle::*, library::*, pipeline::*, renderpass::*, @@ -629,6 +635,14 @@ impl URL { msg_send![class, URLWithString: ns_str] } } + + pub fn new_with_path(path: &str) -> Self { + unsafe { + let ns_str = crate::nsstring_from_str(path); + let class = class!(NSURL); + msg_send![class, fileURLWithPath: ns_str] + } + } } impl URLRef {