読者です 読者をやめる 読者になる 読者になる

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

WritableBitmapその4。ポインタって早いの美味しいの?

WPF C#

結論:結構美味しいよ!!

というわけで、WritableBitmapです。ちょっと寄り道しましたが、まずはマネージドでのベンチマークを取っておきましょう。

測定するのは、今まで作ってきたグラデーションを表示するプログラムを、それぞれWritePixelとポインタアクセスで書き込む処理を行うものです。C#でわざわざポインタを使う意味がどの程度あるのか、確認してみましょう。

コード

まあ、基本的に以前紹介してるのとほぼ同じ手続になります。ほれほれ。

WritePixels使う方
    for (int row = 0; row < ROWS; row++)
    {
        for (int col = 0; col < COLS; col++)
        {
            int index = /*行*/row * COLS + /*列*/col;

            var r = (uint)(redVal * (col + 1) / (double)COLS);
            var g = (uint)(greenVal * (row + 1) / (double)ROWS);
            var b = (uint)blueVal;
            var a = (uint)alphaVal;

            pixels[index] = (r << 16) + (g << 8) + b + (a << 24);
        }
    }

    var stride = (COLS * bitmap.Format.BitsPerPixel + 7) / 8;

    bitmap.WritePixels(
        new Int32Rect(0, 0, COLS, ROWS), //書きこむ領域(ここでは全体)
        pixels, //書きこむデータ
        stride,   //列幅(バイト単位)
        0       //オフセット
        );
ポインタ使う方
    unsafe
    {

        uint* ptrToWb = (uint*)bitmap.BackBuffer;
        for (int row = 0; row < ROWS; row++)
        {
            for (int col = 0; col < COLS; col++)
            {
                var r = (uint)(redVal * (col + 1) / COLS);
                var g = (uint)(greenVal * (row + 1) / ROWS);
                var b = (uint)blueVal;
                var a = (uint)alphaVal;
                *ptrToWb = (r << 16) + (g << 8) + b + (a << 24);
                ptrToWb++;//ポインタを進める
            }
        }
    }
    bitmap.AddDirtyRect(new Int32Rect(0, 0, COLS, ROWS));
    bitmap.Unlock();

結果

WritePixels: 254
Pointer Access: 91
WritePixels: 259
Pointer Access: 99
WritePixels: 256
Pointer Access: 112
WritePixels: 257
Pointer Access: 88
WritePixels: 241
Pointer Access: 90
WritePixels: 244
Pointer Access: 89
WritePixels: 250
Pointer Access: 88

大体2倍くらい違うんですね。
コード的な差異の割には早くなるもんだ!やはり逐次アクセスにはポインターがなかなかに効果的のよう。なれればあっちのほうが読みやすそうだし。
unsafeという怪しげな雰囲気に耐えられるなら、断然こっちですね。

それでは、Nativeコードを使ったやり方を次からは見ていきましょう。