1
votes

I have been rendering polyhedron using Metal. The problem happens when I tried to render an icosahedron entity, whose vertices consists of barely 1680 bytes of data in size using newBufferWithBytes(). Then the entire app halt, both CPU and GPU frame drop to zero, and everything went back to normal, except Metal view freezes.

I have regular polyhedrons as Node's subclasses in implementation.

class Node {
let name : String
var vertexBuffer: MTLBuffer?
var uniformBuffer: MTLBuffer?
var vertexCount : Int = 0

var device : MTLDevice

init(name: String, vertices: [Vertex], device: MTLDevice){
    self.name = name
    self.device = device

    var floatBuffer : [Float] = []
    for vertex in vertices {
        floatBuffer += vertex.floatBuffer
    }
    let floatBufferSize = floatBuffer.count * sizeof(Float)

    self.vertexBuffer = device.newBufferWithBytes(&floatBuffer, length: floatBufferSize, options: nil)
    self.vertexCount = floatBuffer.count
}

func render(commandEncoder: MTLRenderCommandEncoder, parentModelViewMatrix: Matrix4, projectionMatrix: Matrix4){
    commandEncoder.setVertexBuffer(self.vertexBuffer, offset: 0, atIndex: 0)

    // set up uniform transformation matrices
    var nodeModelMatrix = self.modelMatrix()
    nodeModelMatrix.multiplyLeft(parentModelViewMatrix)
    let matrixSize = sizeof(Float) * Matrix4.numberOfElements()
    uniformBuffer = device.newBufferWithLength(matrixSize * 2, options: .OptionCPUCacheModeDefault)
    var bufferPointer = uniformBuffer?.contents()
    memcpy(bufferPointer!, nodeModelMatrix.raw(), matrixSize)
    memcpy(bufferPointer! + matrixSize, projectionMatrix.raw(), matrixSize)
    commandEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, atIndex: 1)

    // can draw
    commandEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: self.vertexCount, instanceCount: 1)
}
}
2

2 Answers

2
votes

Thanks for Ms. Nehal's suggestion. I have modified the answer accordingly.

According to Apple Documentation: Metal Feature Set Tables, with the hardware listed below, Maximum MTLBuffer length are all 256 MB.

Apple A7 ~ A9 GPU on iOS 8 and 9.

OS X 10.11: MacBook (early 2015), MacBook Air (mid 2012 or newer), MacBook Pro (mid 2012 or newer), Mac Mini (late 2012 or newer), iMac (late 2012 or newer), and Mac Pro (late 2013 and newer).

2
votes

Metal Feature Set Tables no longer state maximum MTLBuffer length. Starting with iOS 12 and macOS 10.14 there is a maxBufferLength property on MTLDevice and you should check it when creating larger buffers.

If you just googled this and need a figure to assess viability of some approach without writing any code here are the numbers it gave me.

 - iPad Pro (12.9", 2nd generation) iOS 13.3 - 993 MB (1041235968 bytes)
 - iPhone 11 iOS 13.3 - 960 MB (1007468544 bytes) 
 - iPhone 8 iOS 12.4 - 747 MB (783597568 bytes)
 - iPhone 6 iOS 12.1 - 256 MB (268435456 bytes)

These seem to stay the same across app launches and system restarts. They may change, of course, but they give you an idea. It's probably safe to assume you can always get at least 256MB.