Best Practice: Create persistent objects early and reuse them often.
The Metal framework provides protocols to manage persistent objects throughout the lifetime of your app. These objects are expensive to create but are usually initialized once and reused often. You do not need to create these objects at the beginning of every render or compute loop.
Initialize Your Device and Command Queue First
MTLCreateSystemDefaultDevice function at the start of your app to obtain the default system device. Next, call the
newCommandQueueWithMaxCommandBufferCount: method to create a command queue for executing GPU instructions on that device.
All apps should create only one
MTLDevice object per GPU and reuse it for all your Metal work on that GPU. Most apps should create only one
MTLCommandQueue object per GPU, though you may want more if each command queue represents different Metal work (for example, non-real-time compute processing and real-time graphics rendering).
Compile Your Functions and Build Your Library at Build Time
For an overview of compiling your functions and building your library at build time, see the Functions and Libraries best practices.
At runtime, use the
MTLFunction objects to access your library of graphics and compute functions. Avoid building your library at runtime or fetching functions during a render or compute loop.
If you need to configure multiple render or compute pipelines, reuse
MTLFunction objects whenever possible. You can release
MTLFunction objects after building all render and compute pipelines that depend on them.
Build Your Pipelines Once and Reuse Them Often
Building a programmable pipeline involves an expensive evaluation of GPU state. You should build
MTLComputePipelineState objects only once, then reuse them for every new render or compute command encoder you create. Do not build new pipelines for new command encoders. For an overview of building multiple pipelines asynchronously, see the Pipelines best practices.
Allocate Resource Storage Up Front
Resource data may be static or dynamic and accessed at various stages throughout the lifetime of your app. However, the
MTLTexture objects that allocate memory for this data should be created as early as possible. After these objects are created, the resource properties and storage allocation are immutable, but the data itself is not; you can update the data whenever necessary.
MTLTexture objects as much as possible, particularly for static data. Avoid creating new resources during a render or compute loop, even for dynamic data. For further information about buffers and textures, see the Resource Management and Triple Buffering best practices.