2016-10-31 22 views
3

メタルカーネルのランダムな浮動小数点数を持つバッファの平均値を計算する適切な方法は誰もが知っていますか?メタルカーネルの平均値の計算

threadsPerGroup = MTLSizeMake(1, 1, inputTexture.arrayLength); 
numThreadGroups = MTLSizeMake(1, 1, inputTexture.arrayLength/threadsPerGroup.depth); 

[commandEncoder dispatchThreadgroups:numThreadGroups 
       threadsPerThreadgroup:threadsPerGroup]; 

カーネルコード:

kernel void mean(texture2d_array<float, access::read> inTex [[ texture(0) ]], 
      device float *means       [[ buffer(1) ]], 
      uint3 id          [[ thread_position_in_grid ]]) { 

if (id.x == 0 && id.y == 0) { 
    float mean = 0.0; 
    for (uint i = 0; i < inTex.get_width(); ++i) { 
     for (uint j = 0; j < inTex.get_height(); ++j) { 
       mean += inTex.read(uint2(i, j), id.z)[0]; 
     } 
    } 

    float textureArea = inTex.get_width() * inTex.get_height(); 
    mean /= textureArea; 
    out[id.z] = mean; 
} 

}

バッファがR32Floatピクセルフォーマットとtexture2d_arrayタイプのテクスチャーで表される計算コマンドエンコーダに作業をディスパッチ

答えて

1

データソースとしてuint(浮動小数点数の代わりに)の配列を使用できる場合は、アトミックフェッチおよび変更機能(金属シェーディング言語specで説明)を使用して、アトミックにバッファに書き込むことをお勧めします。

ここで、入力バッファ(データ:フロートの配列)を取り、カーネル関数の一例だと原子バッファ(和、UINTへのポインタ)にバッファの合計を書き込む:

kernel void sum(device uint *data [[ buffer(0) ]], 
       volatile device atomic_uint *sum [[ buffer(1) ]], 
       uint gid [[ thread_position_in_grid ]]) 
{ 
    atomic_fetch_add_explicit(sum, data[gid], memory_order_relaxed); 
} 
あなたの迅速なファイルで

は、あなたがバッファを設定します:

... 
let data: [UInt] = [1, 2, 3, 4] 
let dataBuffer = device.makeBuffer(bytes: &data, length: (data.count * MemoryLayout<UInt>.size), options: []) 
commandEncoder.setBuffer(dataBuffer, offset: 0, at: 0) 

var sum:UInt = 0 
let sumBuffer = device!.makeBuffer(bytes: &sum, length: MemoryLayout<UInt>.size, options: []) 
commandEncoder.setBuffer(sumBuffer, offset: 0, at: 1) 
commandEncoder.endEncoding() 

は、コミット待機してからGPUからデータをフェッチ:

commandBuffer.commit() 
commandBuffer.waitUntilCompleted() 

let nsData = NSData(bytesNoCopy: sumBuffer.contents(), 
         length: sumBuffer.length, 
         freeWhenDone: false) 
nsData.getBytes(&sum, length:sumBuffer.length) 

let mean = Float(sum/data.count) 
print(mean) 

また、初期データソースがfloatの配列でなければならない場合は、AccelerateフレームワークのvDSP_meanvメソッドを使用することができます。

私は助けてくれることを願っています!

+0

フロート値は〜1E-15〜〜1E8まで変化し、負の値もあります。私はそれらをintまたはuintに許容可能な精度でキャストできません。 –