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

Fix type issues in CaptureDescriptor and CaptureManager, add documentation #258

Merged
merged 2 commits into from
Mar 12, 2023
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
25 changes: 25 additions & 0 deletions guide/debugging-in-xcode/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# Saving a GPU trace to a file

GPU command data can be saved to a file using `MTLCaptureManager`. The trace can then be opened and replayed in Xcode at a later time. The following snippet shows how a `CaptureManager` and `CaptureScope` can be used to capture a frame.
kvark marked this conversation as resolved.
Show resolved Hide resolved
```rust
let capture_scope = metal::CaptureManager::shared()
.new_capture_scope_with_device(&metal::Device::system_default().unwrap());

let capture_descriptor = metal::CaptureDescriptor::new();
capture_descriptor.set_capture_scope(&capture_scope);
capture_descriptor.set_output_url(std::path::Path::new(
"~/.../.../framecapture.gputrace",
));
capture_descriptor.set_destination(metal::MTLCaptureDestination::GpuTraceDocument);
metal::CaptureManager::shared().start_capture(&capture_descriptor);

capture_scope.begin_scope();
// Do Metal work
capture_scope.end_scope();
```

> **Warning**
> To capture a GPU trace to a file, you must:
> - Set `METAL_CAPTURE_ENABLED=1` in the environment, or add an `info.plist` containing the `MetalCaptureEnabled` key with a value of `YES`.
> - Ensure the capture descriptor output URL does not already exist.

# Debugging in Xcode

If you only want to enable Metal validation without using Xcode, use the `METAL_DEVICE_WRAPPER_TYPE=1` environment variable when lauching your program. For example, to run the `window` example with Metal validation, use the command `METAL_DEVICE_WRAPPER_TYPE=1 cargo run --example window`.
Expand Down
10 changes: 4 additions & 6 deletions src/capturedescriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,14 @@ impl CaptureDescriptorRef {

/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237250-outputurl>
pub fn output_url(&self) -> &Path {
let output_url = unsafe { msg_send![self, outputURL] };
let output_url = nsstring_as_str(output_url);

Path::new(output_url)
let url: &URLRef = unsafe { msg_send![self, outputURL] };
Path::new(url.path())
}

/// See <https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237250-outputurl>
pub fn set_output_url<P: AsRef<Path>>(&self, output_url: P) {
let output_url = nsstring_from_str(output_url.as_ref().to_str().unwrap());

let output_url_string = String::from("file://") + output_url.as_ref().to_str().unwrap();
let output_url = URL::new_with_string(&output_url_string);
unsafe { msg_send![self, setOutputURL: output_url] }
}

Expand Down
12 changes: 9 additions & 3 deletions src/capturemanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,19 @@ impl CaptureManagerRef {
unsafe { msg_send![self, setDefaultCaptureScope: scope] }
}

/// See <https://developer.apple.com/documentation/metal/mtlcapturemanager/3237259-startcapture>
/// Starts capturing with the capture session defined by a descriptor object.
///
/// This function will panic if Metal capture is not enabled. Capture can be enabled by
/// either:
/// 1. Running from Xcode
/// 2. Setting the environment variable `METAL_CAPTURE_ENABLED=1`
/// 3. Adding an info.plist file containing the `MetalCaptureEnabled` key set to `YES`
pub fn start_capture(&self, descriptor: &CaptureDescriptorRef) -> Result<(), String> {
unsafe {
try_objc! { err =>
Ok(try_objc! { err =>
msg_send![self, startCaptureWithDescriptor: descriptor
error: &mut err]
}
})
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ macro_rules! try_objc {
$err_name: ident => $body:expr
} => {
{
let mut $err_name: *mut ::objc::runtime::Object = ::std::ptr::null_mut();
let mut $err_name: *mut Object = ::std::ptr::null_mut();
let value = $body;
if !$err_name.is_null() {
let desc: *mut Object = msg_send![$err_name, localizedDescription];
Expand Down Expand Up @@ -629,4 +629,11 @@ impl URLRef {
crate::nsstring_as_str(absolute_string)
}
}

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