首页 文章

newComputePipelineStateWithFunction失败

提问于
浏览
11

我试图让一个神经网络在金属上运行 . 基本思想是数据重复 . 每个gpu线程为随机数据点运行一个网络版本 .

我写过其他着色器工作正常 .

我还在c命令行应用程序中尝试了我的代码 . 没有错误 . 也没有编译错误 .

我使用apple文档转换为metal c,因为不支持c 11中的所有内容 .

它在加载内核函数后以及在尝试将 newComputePipelineStateWithFunction 分配给金属设备时崩溃 . 这意味着在编译时未捕获的代码存在问题 .

MCVE:

kernel void net(const device float *inputsVector [[ buffer(0) ]], // layout of net *
                uint id [[ thread_position_in_grid ]]) {

    uint floatSize = sizeof(tempFloat);
    uint inputsVectorSize = sizeof(inputsVector) / floatSize;

    float newArray[inputsVectorSize];


    float test = inputsVector[id];

    newArray[id] = test;

}

Update

它与动态数组有关 .

由于它无法创建管道状态并且不会崩溃运行实际着色器,因此它必须是编码问题 . 不是输入问题 .

将动态数组中的值分配给缓冲区会使其失败 .

2 回答

  • -1

    The real problem: It is a memory issue!

    对于所有人说这是一个记忆问题,你是对的!这里有一些伪代码来说明它 . 对不起,它在“Swift”中,但更容易阅读 . 金属着色器有一种时髦的生活方式 . 它们首先被初始化而没有值来获取内存 . 这一步失败了,因为它依赖于后面的步骤:设置缓冲区 .

    这一切都归结为何时可用的值 . 我对 newComputePipelineStateWithFunction 的理解是错误的 . 它不仅仅是获取着色器功能 . 这也是初始化过程中的一小步 .

    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:

    我终于意识到缓冲区在技术上是动态数组,而不是在着色器中创建数组,我也可以添加更多缓冲区 . 这显然有效 .

  • 4

    我认为你的问题在于这一行:

    uint schemeVectorSize = sizeof(schemeVector) / uintSize;
    

    这里 schemeVectordynamic 所以as in classic C++你不能在动态数组上使用 sizeof 来获取元素数量 . sizeof 仅适用于您在金属着色器代码中本地/静态定义的数组 .

    想象一下它是如何在内部工作的:在编译时,Metal编译器应该将 sizeof 调用转换为常量......但是他不能,因为 schemeVector 是着色器的参数,因此可以有任何大小......

    所以对我来说,解决方案是在代码的C / ObjectiveC / Swift部分计算 schemeVectorSize ,并将其作为参数传递给着色器(作为OpenGLES术语中的统一......) .

相关问题