首页 文章

iOS Metal缓冲区不符合步幅值

提问于
浏览
1

我有一个每实例统一缓冲区,其中缓冲区中的每个元素都是64字节,但我只使用顶点着色器中每个元素的前16个字节(float3) . 我把步伐向上描述了这一点 . 问题是它没有超过其他48个字节 unless 我在着色器中向结构添加填充,以便它也是64个字节 .

// Particle Instance Position
vertexDescriptor.attributes[2].format = .Float3   // 16 bytes with padding.     
vertexDescriptor.attributes[2].offset = 0
vertexDescriptor.attributes[2].bufferIndex = 2
vertexDescriptor.layouts[2].stride = strideof(Particle)
vertexDescriptor.layouts[2].stepFunction = .PerInstance

...

commandEncoder.setVertexBuffer(instanceUniformBuffer, offset:0, atIndex:2)

App侧粒子结构:

struct Particle {

    var position = float3()
    var prevPos = float3()
    var attractPoint = float3()

    var ref: DataRef!
    var state = State.Free

    enum State: Int {
        case Free = 0
        case Active
    }
}

这里是相应的Metal结构,即 Particle.position 对应于着色器中的 InstanceUniforms.instanceTranslate . 我希望上面的步幅设置意味着每个实例都会加载 Particle.position ,并且跳过缓冲区中每个 Particle 的其他48个字节 .

struct InstanceUniforms
{
    float3 instanceTranslate [[ attribute(2) ]];
};

一些健全性检查,一切都有道理:

sizeof(float3) 16
alignof(float3) 16
sizeof(Particle) 57
alignof(Particle) 16
strideof(Particle) 64

但它不起作用,除非我将着色器结构填充到64字节:

struct InstanceUniforms
{
    float3 instanceTranslate [[ attribute(2) ]];
    float4 pad[3];
};

否则对于第二个实例,着色器实际上将 instanceTranslate 设置为缓冲区中 first 元素的 Particle.prevPos ,就像它只跨越 InstanceUniforms 结构的大小一样,无论在顶点描述符中设置了什么步幅 .

我确定我必须在这里做错事,看起来你不应该填充你的着色器结构 .

1 回答

  • 2

    所以看起来这就是Just The Way It Is™with Metal缓冲区:你必须填充着色器结构以匹配app结构的步幅 . 我不认为Metal Shader运行时从缓冲区加载 stride 字节并转换它们的第一个 sizeof(MyShaderStruct) 会很困难 . 或者在附加管道状态时自动加载结构 . 但这些便利可能具有效率影响 .

    这是我的Swift / Shader结构现在的样子供参考:

    Metal:

    struct Particle
    {
       float3 position;
       float3 prevPos;
       float4 color;
       float4 lineColor;
       float  scale;
       char   pad[60];
    };
    

    Swift:

    struct Particle {
        var position = float3()
        var prevPos = float3()
        var color = float4()
        var lineColor = float4()
        var scale:Float = 0
        var gravity = float3()
    
        var data: DataRef!
        weak var physics: Physics? = nil
        var state = State.Free
    
        enum State: Int {
            case Free = 0
            case Active
        }
    }
    
    sizeof(Particle) 113
    alignof(Particle) 16
    strideof(Particle) 128
    

相关问题