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

亀岡的プログラマ日記

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

WritableBitmapをちびちび(ry その3。unsafeって中二病的な響きだよね。

短期集中連載、WritableBitmap!

さて、前回までのコードは、

  • Byte型やuint型の配列作って、
  • それをWritePixelで描画!

でした。いわばバックバッファのように配列を扱っていたんですね。
ところがWritableBitmapにはBackBufferプロパティがあって、ちゃんと要素数分の領域が確保されてたりします。

BackBuffer バック バッファーへのポインターを取得します。

ので、単純に絵を作るのなら、こちらに直接放り込むべきですよね。
しかしポインターですか・・・。よろしい、ならばunsafeだ。
定義しましょう。プロジェクトのプロパティで許可しといてくださいねん。あとWritableBitmapのコンストラクターとかは前回と基本同じですよ。

           unsafe
            {
                uint* ptrToWb = (uint*)bitmap.BackBuffer;

            }

ちなみに、BackBufferを使う場合は

解説
バック バッファーには、ビットマップのコンテンツが、ユーザーによって指定されたピクセル形式で格納されます。 バック バッファーの更新は、Lock メソッドの呼び出しと Unlock メソッドの呼び出しの間にだけ行います。 WriteableBitmap クラスの解説で説明したロック/ロック解除ワークフローに従わない場合は、ティアリングなどの未定義の動作が行われる可能性があります。 バック バッファーのアドレスは変更されません。
スレッド セーフ
処理のために BackBuffer ポインターを外部コンポーネントおよび他のスレッドに渡すことができますが、この場合は独自のスレッド調整が必要です。 特に、AddDirtyRect メソッドを呼び出して UI スレッドが変更された領域を指定すること、および Unlock メソッドの呼び出して UI スレッドがバッファーのロックを解除することを確認する必要があります。
というわけで、古式ゆかしい実装をしてやる必要があります。 こんな感じ。
            bitmap.Lock();
            unsafe
            {
                uint* ptrToWb = (uint*)bitmap.BackBuffer;
                //なんか処理
            }
            bitmap.AddDirtyRect(new Int32Rect(0, 0, COLS, ROWS));
            bitmap.Unlock();
例えば、赤成分を縦方向に、緑成分を横方向に、それぞれグラデーションさせるとこんな感じ。
            bitmap.Lock();
            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();
おお、なんかマネージドに見えない。そいではこのあたりで速度比較でもやってみましょうか。