I have successfully used Metal to render into a simple view, and update at full FPS, by following and modifying the code at https://github.com/jim-ec/metal-hello-triangle
I am now trying to repeat the process by drawing into multiple views in an NSCollectionView.
My render code is as follows, where each view in the NSCollectionView has a global Renderer object as its delegate:
class Renderer {
/// Initialisation as per the linked tutorial
public func draw(in view: MTKView)
{
let dataSize = VERTEX_DATA.count * MemoryLayout.size(ofValue: VERTEX_DATA[0])
VERTEX_DATA[1][1] = Float(arc4random_uniform(100)) / 100
let vertexBuffer = view.device?.makeBuffer(bytes: VERTEX_DATA,
length: dataSize,
options: [])
let commandBuffer = mCommandQueue.makeCommandBuffer()!
let commandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: view.currentRenderPassDescriptor!)
commandEncoder?.setRenderPipelineState(mPipeline)
commandEncoder?.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
commandEncoder?.drawPrimitives(type: .triangle,
vertexStart: 0,
vertexCount: 3,
instanceCount: 1)
commandEncoder?.endEncoding()
commandBuffer.present(view.currentDrawable!)
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
}
}
The arc4random_uniform call is to make the triangles change colour, so I can confirm that they are redrawing.
Unfortunately, views only update around 3 times a second, and not at all in sync. Looking at instruments, the GPU is barely breaking a sweat, and the CPU overhead of both WindowServer and my app are pretty huge. The draw function is now very heavy with makeRenderCommandEncoder becoming a real bottleneck, and there are obviously some synchronisation issues given the sporadic updating.
I expected this to be more-or-less similar performance as I'm still doing a trivial amount of drawing, but it really isn't. What am I doing wrong?
Working example available at https://github.com/SirWhiteHat/MetalPerformanceProblem
Thank you!

