2017-09-01 6 views
1

私は私の質問に2つのセクションがあります。私は0から変化する色(RGB)の3つの値を含む構造通過しなければならない要件有するMetalのフラグメントシェーダ内でstructオブジェクトに正しくアクセスできませんか?

第一部

を1 - それはターン値をハードコーディングしたコードをテストしたときに受け取った値が何であっても違います。ここで

は私が

let colors = color.floatBuffers() 

    let colorBuffer = device.makeBuffer(bytes: colors, length: 16, options: []) 
    renderEncoder.setFragmentBuffer(colorBuffer, offset: 0, at: 0) 

でもあれば、このようなフラグメントにバッファを渡し、私の迅速な構造は次のようになります私のフラグメントシェーダ方法

struct RGBColors { 
    half red; 
    half green; 
    half blue; 
}; 
fragment float4 
samplingShader(RasterizerData in [[stage_in]], 
       texture2d<half> colorTexture [[ texture(0) ]], 
       const device struct RGBColors *color [[ buffer(0) ]] 
) 
{ 
    constexpr sampler textureSampler (mag_filter::linear, 
             min_filter::linear, 
             s_address::repeat, 
             t_address::repeat, 
             r_address::repeat); 
     const half4 colorSample = colorTexture.sample (textureSampler, in.textureCoordinate); 

    float4 outputColor = float4(0,0,0,0); 

    half red = color->red; 
    half blue = color->blue; 
    half green = color->green; 

    outputColor = float4(colorSample.r * red, colorSample.g * green, colorSample.b * blue, 0); 

    return outputColor; 
} 

ある

struct RGBColors { 
    var r: Float 
    var g: Float 
    var b: Float 

    func floatBuffers() -> [Float] { 
     return [r,g,b] 
    } 
} 

私はこのconstant float3 *color [[ buffer(0) ]]のようにfloat3にconst device struct RGBColors *color [[ buffer(0) ]]のパラメータの色を変更し、それは正しく動作するrgb値を介してアクセスします。

第二部

あなたは let colorBuffer = device.makeBuffer(bytes: colors, length: 16, options: [])で長さが16であるが、私は

`MemoryLayout.size(ofValue: colors[0]) * colors.count` 

に変更した場合、それは

`failed assertion `(length - offset)(12) must be >= 16 at buffer binding at index 0 for color[0].'` 
をクラッシュと言っているというのが私のコードで見ることができるように

何が起こっているのか把握できません。誰かが私を提案することができます。

ありがとうございました。

答えて

1

スウィフトFloatタイプは、金属halfタイプには対応していません。私の知る限り、Swiftにはhalfの良い表現はありません(または、その点でCまたはObjective-Cです)。 3つの32ビット値を3つの16ビット値が必要なものに提供しています。あなたが提供している値は、受信側のコードがどのようにそれらにアクセスするかと一致しないので、値の下位部分にアクセスしています。

シェーダのhalfを使用してfloatに切り替えることをお勧めします。これはSwiftでより簡単に表現できます。

次に、RGBColors構造体は組み込み型half3で基本的に冗長です。上記のアドバイスを受けた場合は、float3です。だから、私はちょうどfloat3を使用することをお勧めします。あなたがimport simdなら、そのタイプはSwiftでも利用可能です。メタル(およびC)では、.r,.g,.bまたは.x,.y,のいずれかを使用してメンバーにアクセスできますが、スウィフトは後者のみをサポートするようです。どちらの言語も、配列の添字構文を使用してメンバーにアクセスすることをサポートしています。 MemoryLayout overviewに記載されているようにバッファサイズやオフセットを計算する際

、あなたはsizeプロパティまたはsize(ofValue:)メソッドを使用しないでください。stride/stride(ofValue:)を使用してください。さらに、複合型の1つの要素のストライドに要素数を乗じて使用しないでください。複合型全体のストライドを使用する必要があります。これは、コンパイラーがアラインメント要件を維持するために複合型にパディングを追加することができ、前者の手法では考慮していないためです。

最後の注意:シェーダーでは、color変数は単一の色にしかアクセスできません。つまり、色の配列ではありません。したがって、ポインタ型ではなく参照型として宣言してください。これによりコンパイラはより良いコードを生成できるようになります。もちろん

const device float3 &color [[ buffer(0) ]] 

、あなたはcolor.color->を変更する必要があると思います。

+0

それはうまくいった。しかし、私は 'MemoryLayout.stride(ofValue:colors)'を使用してバッファImのバッファ長に渡すと、クラッシュが '失敗アサーション(length-offset) 'になっても、なぜ私はまだクラッシュするのか理解できません。 (8)は、color [0]のインデックス0のバッファバインディングで16以上でなければなりません。しかし、 'float3 'ではなく' MemoryLayout.stride(ofValue:colors [0])* colors.count'を使用すると、 '型パラメータ。なぜ私に提案することができますか? –

+0

'float3'型にはパディングがあります。そのストライドは、単一の 'float' /' Float'のサイズの3倍の** **ではありません。 Metal Shaderの言語仕様(2.9節、表3)をチェックすると、 'float3'のサイズと配置が16バイトであることがわかります。そのため、1つの要素のストライドを取得し、それを要素の数で掛けることは有効ではありません。あなたは間違った結果を得る。明らかに値8を与える 'MemoryLayout.stride(ofValue:colors)'に関しては、 'colors'は単純なバッファではないSwift配列です。内部レイアウトが不明なオブジェクトです。それをやろうとしないでください。 –

関連する問題