3-9. ファイルに書き出してみる

この節では前節までで描画した(はず)の画像データを実際にファイルに書き出して見てみます。

見ることは出来ないが描画は行われたのだ…と信じることのできる人は見なくても構いませんが、「これ本当にちゃんと動いてるの?」という心はエンジニアにとって重要だということはお伝えしたいと思います。

画像ファイルを簡単に扱うために、stbと呼ばれる簡単に使えるヘッダライブラリを利用します。

まずはこちらからstb_image_write.hというヘッダファイルをダウンロードし、ソースファイルと同じ場所に配置してください。配置出来たら、メインのソースファイルで以下のようにインクルードとシンボル定義を書きます。

これで利用する準備は完了です。

stb_image_writeライブラリを使うと簡単に画像ファイルを書き出すことができます。今回はbmpファイルで書き出してみましょう。 stbi_write_bmp 関数を使って行えます。

引数はそれぞれファイル名、幅、高さ、1画素当たりのバイト数、データです。第4引数が4のとき、それぞれの画素はRGBAをこの順でそれぞれ1バイト(符号なし8ビット)で表します。(ここはVulkanとは関係ない部分なので端折ります)

さて、画像のデータを取り出したいところですが、どこにあるのでしょう。3-2. メモリの確保で書いた内容を復習してください。データはメインメモリではなくGPUの中にあります。つまりこのままではアプリケーションからアクセスできません。そこでアプリケーション側のアドレス空間上にマップして、メインのプログラムから見れるようにする必要があります。そしてそれにはちょっとした段取りが必要です。

「GPU上のメモリには種類があり、適切に選択する必要がある」と書いたのを覚えていますでしょうか。実はGPU上のメモリには、GPUを扱うコンピュータ・アプリケーションの側(ホストと呼びます)からアクセスできるものとアクセスできないものがあります。そこで、メモリを確保するところで「目的のイメージにバインドできるメモリ」であるだけでなく「ホスト側から見えるメモリ」であるメモリを選択する必要があります。

具体的には以下のようにします。

i番目の種類のメモリタイプのプロパティを見て、HostVisible(ホスト側から見える)であることを確認しています。

これで準備が出来ました。GPUの描画処理が終わった後のところに処理を書いていきましょう。

マッピングは vk::devicemapMemory メソッドで行います。

第1引数はメモリオブジェクト、第2引数はデバイスメモリのマップしたい場所のオフセット、第3引数はマップするサイズです。第2引数と第3引数を使えば先頭から何バイト目の所から何バイト分の部分だけを扱う、ということもできますが、ここでは全部見たいのでこのようにしています。戻り値はマップされた場所のアドレスです。この imgData にアクセスすれば画像の生データにアクセスできます。

早速書き出してしまいましょう。

マップしたメモリはきちんと後始末します。

さて、無事img.bmpというファイル名で画像は書き出されましたでしょうか。筆者の環境ではこのようになりました。

やりました!無事赤い三角形が描画出来ています!なんかちょっと背景が紫ですが。

描画した以外の部分は何も触っていないので、そこがどのようになるかは未定義です。ちょっと気持ち悪いですね。そこで、レンダーパスの設定で描画処理が始まる前に一度アタッチメント全体を特定の色でクリアすることができます。具体的には以下のようにします。

アタッチメントの設定で loadOpeClear を指定します。

どのような色でクリアするかの設定をレンダーパス開始コマンドの際に行います。ここでは(0.0, 0.0, 0.0, 1.0)、RGBが0でアルファだけ1ということは真っ黒でクリアすることになります。実行してみましょう。

黒と赤になりました。


この節では、前節までで三角形の描画がきちんと出来ていたことをファイルに書き出して確認しました。

次章ではウィンドウへの表示をやります。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です