<!--
{
  "documentType" : "article",
  "framework" : "Metal",
  "identifier" : "/documentation/Metal/transferring-data-between-connected-gpus",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Transferring data between connected GPUs"
}
-->

# Transferring data between connected GPUs

Use high-speed connections between GPUs to transfer data quickly.

## Discussion

In macOS 10.15 and later, some Mac systems directly connect GPUs to each other, allowing you to quickly transfer data between them. These connections are not only faster, but they also avoid using the memory bus between the CPU and GPUs, leaving it available for other tasks. If your app uses multiple GPUs, test to see if they’re connected, and when they are, use the transfer mechanism described here.

When GPUs are connected to each other, they’re said to be in the same *peer group*. You determine whether a GPU is in a peer group by reading the device instance’s [`peerGroupID`](/documentation/Metal/MTLDevice/peerGroupID) property. A nonzero value indicates that the GPU is in a peer group.

```objective-c
bool isMemberOfAnyPeerGroup(id<MTLDevice> device)
{
    return (device.peerGroupID != 0);
}
```

GPUs in the same peer group share the same peer group ID.

```objective-c
bool areMembersOfSamePeerGroup(id<MTLDevice> deviceA, id<MTLDevice> deviceB)
{
    return (isMemberOfAnyPeerGroup(deviceA) &&
            deviceA.peerGroupID == deviceB.peerGroupID);
}
```

You can get the list of all devices associated with a peer group by filtering on this ID.

```objective-c
NSArray<id<MTLDevice>>* devicesInPeerGroup(uint64_t peerGroupID)
{
    if (peerGroupID == 0)
    {
        return @[];
    }
    return [MTLCopyAllDevices() filteredArrayUsingPredicate: [NSPredicate predicateWithFormat:@"SELF.peerGroupID == %uul", peerGroupID]];
}
```

### Copy resources to the GPU that needs to access them

In Metal, resources are created by device instances, and are always associated with the device instance that created them. Peer groups don’t change that association. If a resource is associated with a device instance, and you want to access it on another device instance, you need to copy the data to a resource associated with the second device instance.

To copy data between members of a peer group, make a *remote view* on the second GPU that’s connected to the resource you want to copy. A remote view is a resource instance that contains no storage of its own; it references the storage on the original GPU. You can only use remote views to copy data; using them in other Metal commands results in an error.

### Create a remote view of a resource

To create a remote view of a resource, the device instance you make the resource view on needs to share the same [`peerGroupID`](/documentation/Metal/MTLDevice/peerGroupID) as the device instance that created the resource. In addition, the resource needs to use the [`MTLStorageMode.private`](/documentation/Metal/MTLStorageMode/private) storage mode or be backed by an <doc://com.apple.documentation/documentation/IOSurface/IOSurface>.

To create a buffer view, call the [`makeRemoteBufferView(_:)`](/documentation/Metal/MTLBuffer/makeRemoteBufferView(_:)) method:

```objective-c
id<MTLBuffer> remoteBufferView = [sourceBuffer newRemoteBufferViewForDevice:otherDevice];
```

Similarly, to create a texture view, call the [`makeRemoteTextureView(_:)`](/documentation/Metal/MTLTexture/makeRemoteTextureView(_:)) method.

```objective-c
id<MTLTexture> remoteTextureView = [sourceTexture newRemoteTextureViewForDevice:otherDevice];
```

### Copy data between connected GPUs

Create an [`MTLBlitCommandEncoder`](/documentation/Metal/MTLBlitCommandEncoder) and encode a copy command. The source for this copy command is the remote view instance:

```objective-c
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
[blitEncoder copyFromBuffer:remoteBufferView sourceOffset:0
                   toBuffer:destinationBuffer destinationOffset:0
                       size:remoteBufferView.allocatedSize];
[blitEncoder copyFromTexture:remoteTextureView
                   toTexture:destinationTexture];
[blitEncoder endEncoding];
```

As shown in the following illustration, there are three resource instances: the original resource that contains the data, a remote view that references the data, and a resource that receives the data.

![A figure showing two devices. The source buffer or texture is created by the first device. The second device has a remote view of the source texture and a destination texture.](images/com.apple.metal/transferring-data-between-connected-gpus-1@2x.png)

### Synchronize access to resources

Blit commands used in peer-to-peer transfers follow all of the usual synchronization rules on the GPU they’re performed on. However, they don’t automatically synchronize with any commands running on the source GPU. If you encode commands that modify the source resource, ensure that those commands are complete before executing the blit command to transfer the data to the other GPU. This is the same as what you do when transferring resources between GPUs through system memory.

To synchronize commands between different device instances, use shared events. See [Synchronizing events across multiple devices or processes](/documentation/Metal/synchronizing-events-across-multiple-devices-or-processes) and [Implementing a multistage image filter using heaps and events](/documentation/Metal/implementing-a-multistage-image-filter-using-heaps-and-events).

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)