Guides and Sample Code

Developer

Metal Best Practices Guide

Pipelines

Best Practice: Build your render and compute pipelines asynchronously.

Having multiple render or compute pipelines allows your app to use different state configurations for specific tasks. Building these pipelines asynchronously maximizes performance and parallelism. Build all known pipelines up front and avoid lazy loading. Listing 14-1 shows how to build multiple render pipelines asynchronously.

Listing 14-1Building multiple render pipelines asynchronously
  1. const uint32_t pipelineCount;
  2. dispatch_queue_t dispatch_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  3. // Dispatch the render pipeline build
  4. __block NSMutableArray<id<MTLRenderPipelineState>> *pipelineStates = [[NSMutableArray alloc] initWithCapacity:pipelineCount];
  5. dispatch_group_t pipelineGroup = dispatch_group_create();
  6. for(uint32_t pipelineIndex = 0; pipelineIndex < pipelineCount; pipelineIndex++)
  7. {
  8. id <MTLFunction> vertexFunction = [_defaultLibrary newFunctionWithName:vertexFunctionNames[pipelineIndex]];
  9. id <MTLFunction> fragmentFunction = [_defaultLibrary newFunctionWithName:fragmentFunctionNames[pipelineIndex]];
  10. MTLRenderPipelineDescriptor* pipelineDescriptor = [MTLRenderPipelineDescriptor new];
  11. pipelineDescriptor.vertexFunction = vertexFunction;
  12. pipelineDescriptor.fragmentFunction = fragmentFunction;
  13. /* Configure additional descriptor properties */
  14. dispatch_group_enter(pipelineGroup);
  15. [_device newRenderPipelineStateWithDescriptor:pipelineDescriptor completionHandler: ^(id <MTLRenderPipelineState> newRenderPipeline, NSError *error )
  16. {
  17. // Add error handling if newRenderPipeline is nil
  18. pipelineStates[pipelineIndex] = newRenderPipeline;
  19. dispatch_group_leave(pipelineGroup);
  20. }];
  21. }
  22. /* Do more work */
  23. // Wait for build to complete
  24. dispatch_group_wait(pipelineGroup, DISPATCH_TIME_FOREVER);
  25. /* Use the render pipelines */