newComputePipelineStateWithFunction failed

本秂侑毒 提交于 2019-12-01 15:27:35

The real problem: It is a memory issue!

To all the people saying that it was a memory issue, you were right! Here is some pseudo code to illustrate it. Sorry that it is in "Swift" but easier to read. Metal Shaders have a funky way of coming to life. They are first initialised without values to get the memory. It was this step that failed because it relied on a later step: setting the buffer.

It all comes down to which values are available when. My understanding of newComputePipelineStateWithFunction was wrong. It is not simply getting the shader function. It is also a tiny step in the initialising process.

class MetalShader {

    // buffers
    var aBuffer : [Float]
    var aBufferCount : Int

    // step One : newComputePipelineStateWithFunction
    memory init() {
        // assign shader memory

        // create memory for one int
        let aStaticValue : Int
        // create memory for one int
        var aNotSoStaticValue : Int // this wil succeed, assigns memory for one int

        // create memory for 10 floats
        var aStaticArray : [Float] = [Float](count: aStaticValue, repeatedValue: y) // this will succeed

        // create memory for x floats
        var aDynamicArray : [Float] = [Float](count: aBuffer.count, repeatedValue: y) // this will fail
        var aDynamicArray : [Float] = [Float](count: aBufferCount, repeatedValue: y) // this will fail

        let tempValue : Float // one float from a loop

    }

    // step Two : commandEncoder.setBuffer()
    assign buffers (buffers) {

        aBuffer = cpuMemoryBuffer

    }

    // step Three : commandEncoder.endEncoding()
    actual init() {
        // set shader values

        let aStaticValue : Int = 0

        var aNotSoStaticValue : Int = aBuffer.count

        var aDynamicArray : [Float] = [Float](count: aBuffer.count, repeatedValue: 1) // this could work, but the app already crashed before getting to this point.

    }

    // step Four : commandBuffer.commit()
    func shaderFunction() {
        // do stuff
        for i in 0..<aBuffer.count {

            let tempValue = aBuffer[i]

        }
    }
}

Fix:

I finally realised that buffers are technically dynamic arrays and instead of creating arrays inside the shader, I could also just add more buffers. This obviously works.

VB_overflow

I think your problem is with this line :

uint schemeVectorSize = sizeof(schemeVector) / uintSize;

Here schemeVector is dynamic so as in classic C++ you cannot use sizeof on a dynamic array to get number of elements. sizeof would only work on arrays you would have defined locally/statically in the metal shader code.

Just imagine how it works internally : at compile time, the Metal compiler is supposed to transform the sizeof call into a constant ... but he can't since schemeVector is a parameter of your shader and thus can have any size ...

So for me the solution would be to compute schemeVectorSize in the C++/ObjectiveC/Swift part of your code, and pass it as a parameter to the shader (as a uniform in OpenGLES terminology ...).

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!