title: Rendering to CVPixelBuffer on iOS
body: <p>I have a flutter plugin where I need do to some basic 3D rendering on iOS.
  I decided to go with the Metal API because the OpenGL ES is deprecated on the platform.</p>
  <p>Before implementing a plugin I implemented rendering in the iOS application. There rendering works without problems.</p>
  <p>While rendering to the texture I get whole area filled with black.</p>
  <pre class="lang-swift prettyprint-override"><code>//preparation
  Vertices = [Vertex(x:  1, y: -1,   tx: 1, ty: 1),
              Vertex(x: 1, y:  1,   tx: 1, ty: 0),
              Vertex(x: -1, y:  1,  tx: 0, ty: 0),
              Vertex(x:  -1, y:  -1,  tx: 0, ty: 1),]
  Indices = [0, 1, 2, 2, 3, 0]
  
  let d = [
      kCVPixelBufferOpenGLCompatibilityKey : true,
      kCVPixelBufferMetalCompatibilityKey : true
  ]
  var cvret = CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, d as CFDictionary, &amp;pixelBuffer); //FIXME jaki format
  if(cvret != kCVReturnSuccess) {
      print(&quot;faield to create pixel buffer&quot;)
  }
  
  metalDevice = MTLCreateSystemDefaultDevice()! 
  
  let desc = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.rgba8Unorm, width: width, height: height, mipmapped: false)
  desc.usage = MTLTextureUsage.renderTarget.union( MTLTextureUsage.shaderRead )
  targetTexture = metalDevice.makeTexture(descriptor: desc)
  metalCommandQueue = metalDevice.makeCommandQueue()!  
  ciCtx = CIContext.init(mtlDevice: metalDevice)
  
  let vertexBufferSize = Vertices.size()
  vertexBuffer = metalDevice.makeBuffer(bytes: &amp;Vertices, length: vertexBufferSize, options: .storageModeShared)
  
  let indicesBufferSize = Indices.size()
  indicesBuffer = metalDevice.makeBuffer(bytes: &amp;Indices, length: indicesBufferSize, options: .storageModeShared)
  
  let defaultLibrary = metalDevice.makeDefaultLibrary()!
  let txProgram = defaultLibrary.makeFunction(name: &quot;basic_fragment&quot;)
  let vertexProgram = defaultLibrary.makeFunction(name: &quot;basic_vertex&quot;) 
  
  let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
  pipelineStateDescriptor.sampleCount = 1
  pipelineStateDescriptor.vertexFunction = vertexProgram
  pipelineStateDescriptor.fragmentFunction = txProgram
  pipelineStateDescriptor.colorAttachments[0].pixelFormat = .rgba8Unorm
  
  pipelineState = try! metalDevice.makeRenderPipelineState(descriptor: pipelineStateDescriptor)
  
  //drawing
  let renderPassDescriptor = MTLRenderPassDescriptor() 
  renderPassDescriptor.colorAttachments[0].texture = targetTexture 
  renderPassDescriptor.colorAttachments[0].loadAction = .clear 
  renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.85, green: 0.85, blue: 0.85, alpha: 0.5) 
  renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreAction.store
  renderPassDescriptor.renderTargetWidth = width
  renderPassDescriptor.renderTargetHeight = height
  
  guard let commandBuffer = metalCommandQueue.makeCommandBuffer() else { return }
  
  guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { return }
  renderEncoder.label = &quot;Offscreen render pass&quot;
  renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0) 
  
  renderEncoder.setRenderPipelineState(pipelineState)
  renderEncoder.drawIndexedPrimitives(type: .triangle, indexCount: Indices.count, indexType: .uint32, indexBuffer: indicesBuffer, indexBufferOffset: 0) // 2
  
  renderEncoder.endEncoding() 
  commandBuffer.commit() 
  
  //copy to pixel buffer
  guard let img = CIImage(mtlTexture: targetTexture) else { return }
  ciCtx.render(img, to: pixelBuffer!)
  </code></pre>