Synchronizing a managed resource in macOS
Manually synchronize memory for a Metal resource in apps.
Overview
For Mac computers with Intel or external GPUs, Metal offers managed resources. Managed resources are MTLResource instances, such as an MTLTexture or MTLBuffer, which use memory that your app can copy between the CPU and GPU. Managed resources use a storageMode of MTLStorageMode.managed.
You need to manually synchronize managed resources, copying changed memory between the CPU and GPU. This is different from Apple family GPUs, which use MTLStorageMode.shared for resources that the CPU and GPU can both access. Synchronize after your code finishes memory writes. After data synchronizes, you can safely read it in both your app and GPU functions.
As a best practice, try to keep your data synchronization points to a minimum. Even synchronization calls which don’t copy data can result in a small performance hit.
Synchronize a managed buffer
First, create an MTLBuffer with the option MTLStorageMode.managed, which tells Metal to reserve managed memory space for the resource:
Next, modify the buffer’s data on the CPU:
After completing a CPU modification, call the didModifyRange: method. This method updates a specific range of data and keeps the buffer synchronized. Before calling this method, the modified buffer’s data on the GPU is in an undefined state.
After encoding a GPU modification, encode a synchronize(resource:) command. This command updates the entire buffer and keeps it synchronized. Before executing this command, the modified buffer’s data on the CPU is in an undefined state.
Synchronize a managed texture
First, create an MTLTexture in managed memory from an MTLTextureDescriptor with its storage mode set to MTLStorageMode.managed:
To perform a CPU modification and simultaneously notify Metal about the change, call the replace(region:mipmapLevel:withBytes:bytesPerRow:) method. This method updates a specific region of data and keeps the texture synchronized. To update a specific texture slice, call the replace(region:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:) method instead. Before calling one of these methods, the modified texture’s data on the GPU is in an undefined state.
After encoding a GPU modification, encode a synchronize(resource:) command. This command updates the entire texture and keeps it synchronized. To update a specific texture slice or mipmap level, encode the synchronize(texture:slice:level:) command instead. Before executing this command, the modified texture’s data on the CPU is in an undefined state.