AAPLRenderer.m 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. See LICENSE folder for this sample’s licensing information.
  3. Abstract:
  4. Implementation of a platform independent renderer class, which performs Metal setup and per frame rendering
  5. */
  6. @import simd;
  7. @import MetalKit;
  8. #import "AAPLRenderer.h"
  9. // Header shared between C code here, which executes Metal API commands, and .metal files, which
  10. // uses these types as inputs to the shaders.
  11. #import "AAPLShaderTypes.h"
  12. // Main class performing the rendering
  13. @implementation AAPLRenderer
  14. {
  15. id<MTLDevice> _device;
  16. // The render pipeline generated from the vertex and fragment shaders in the .metal shader file.
  17. id<MTLRenderPipelineState> _pipelineState;
  18. // The command queue used to pass commands to the device.
  19. id<MTLCommandQueue> _commandQueue;
  20. // The current size of the view, used as an input to the vertex shader.
  21. vector_uint2 _viewportSize;
  22. }
  23. - (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
  24. {
  25. self = [super init];
  26. if(self)
  27. {
  28. NSError *error;
  29. _device = mtkView.device;
  30. // Load all the shader files with a .metal file extension in the project.
  31. id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
  32. id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
  33. id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];
  34. // Configure a pipeline descriptor that is used to create a pipeline state.
  35. MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
  36. pipelineStateDescriptor.label = @"Simple Pipeline";
  37. pipelineStateDescriptor.vertexFunction = vertexFunction;
  38. pipelineStateDescriptor.fragmentFunction = fragmentFunction;
  39. pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;
  40. _pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor
  41. error:&error];
  42. // Pipeline State creation could fail if the pipeline descriptor isn't set up properly.
  43. // If the Metal API validation is enabled, you can find out more information about what
  44. // went wrong. (Metal API validation is enabled by default when a debug build is run
  45. // from Xcode.)
  46. NSAssert(_pipelineState, @"Failed to create pipeline state: %@", error);
  47. // Create the command queue
  48. _commandQueue = [_device newCommandQueue];
  49. }
  50. return self;
  51. }
  52. /// Called whenever view changes orientation or is resized
  53. - (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
  54. {
  55. // Save the size of the drawable to pass to the vertex shader.
  56. _viewportSize.x = size.width;
  57. _viewportSize.y = size.height;
  58. }
  59. /// Called whenever the view needs to render a frame.
  60. - (void)drawInMTKView:(nonnull MTKView *)view
  61. {
  62. static const AAPLVertex triangleVertices[] =
  63. {
  64. // 2D positions, RGBA colors
  65. { { 250, -250 }, { 1, 0, 0, 1 } },
  66. { { -250, -250 }, { 0, 1, 0, 1 } },
  67. { { 0, 250 }, { 0, 0, 1, 1 } },
  68. };
  69. // Create a new command buffer for each render pass to the current drawable.
  70. id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
  71. commandBuffer.label = @"MyCommand";
  72. // Obtain a renderPassDescriptor generated from the view's drawable textures.
  73. MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
  74. if(renderPassDescriptor != nil)
  75. {
  76. // Create a render command encoder.
  77. id<MTLRenderCommandEncoder> renderEncoder =
  78. [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
  79. renderEncoder.label = @"MyRenderEncoder";
  80. // Set the region of the drawable to draw into.
  81. [renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, 0.0, 1.0 }];
  82. [renderEncoder setRenderPipelineState:_pipelineState];
  83. // Pass in the parameter data.
  84. [renderEncoder setVertexBytes:triangleVertices
  85. length:sizeof(triangleVertices)
  86. atIndex:AAPLVertexInputIndexVertices];
  87. [renderEncoder setVertexBytes:&_viewportSize
  88. length:sizeof(_viewportSize)
  89. atIndex:AAPLVertexInputIndexViewportSize];
  90. // Draw the triangle.
  91. [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
  92. vertexStart:0
  93. vertexCount:3];
  94. [renderEncoder endEncoding];
  95. // Schedule a present once the framebuffer is complete using the current drawable.
  96. [commandBuffer presentDrawable:view.currentDrawable];
  97. }
  98. // Finalize rendering here & push the command buffer to the GPU.
  99. [commandBuffer commit];
  100. }
  101. @end