2010年02月17日

Blender2.5 Vectexビルド

2ヶ月以上もの間まったく更新がなくてすみませんでした。
Blender2.5へのVectexの組み込みがある程度形になったので、Graphicall.orgでダウンロードできるように公開しました。
pic100216_01.jpg

Blender2.5 r26884

Linux 64bit

Linux 32bit

Windows 32bit

ソースファイルのパッチ(Blender2.5_Vectex_patch.zip)


できれば前回のBlender2.49と同等の機能を組み込んだ状態で公開したかったのですが、それにはもう少し時間がかかりそうです。

まだ実装できていない機能は、ノード機能とビデオシーケンスエディタの機能です。
それ以外にも、
Blender2.5ではプロパティパネルのほとんどの機能をアニメーション化できるようなのですが、Vectexパネルのプロパティは現在のところアニメーションに対応していません。
3D ViewのバックグラウンドイメージとしてSVG画像を表示する場合、タイル画像の境界が表示されます。
というような問題があります。

Blender2.5ではBlender2.49とくらべて様々な機能変更が行われています。
ただし、Vectexが直接関係するテクスチャの機能についてはほとんど変更はありません。
私は当初、ユーザーインターフェイス以外の部分はほとんど変更を加えることなしに、Blender2.49のソースコードをそのままBlender2.5でも使えると考えていました。
ユーザーインターフェイス部分がかなり大きく変更されているのは確かで、Vectexのパネルを動くようにするのにかなり時間がかかりました。
しかし、それ以外にも色々と問題があってソースコードにかなり変更を加える必要がありました。

今回はそのあたりのことを記事にしてみたいと思います。

○アニソトロピックフィルタリング
Blender2.5のProperty EditorでTextureを選択すると「Image Sampling」というパネルがあります。
このパネルの「Filter:」という項目のドロップダウンメニューでフィルタタイプを選べるようになっています。
Blender2.49ではBoxサンプリングのみが利用可能でしたが、Blender2.5ではそれ以外にもEWA、FELINE、Area、SATなどが追加されました。
pic100216_02.jpg

これについてBlenderのリリースログでも少しだけ説明があります。
http://www.blender.org/development/release-logs/blender-250/other-rendering-features/

リリースログの説明だけではBoxサンプリングと何が違うのか詳しいことまではわからないのですが、ソースコードの中ではanisotoropic filteringという言葉が使われています。

アニソトロピックフィルタリングというのは何かというと、実は私もつい最近まで全然詳しい仕組みを知らなかったのですが、ミップマップの処理を行う際にテクスチャ座標の水平方向と奥行き方向とを分けて処理することらしいです。

VectexでSVGを使用した場合(左)と、通常のPNG画像を使用した場合(右)の各フィルタタイプの比較画像です。
pic100216_03.jpg pic100216_04.jpg

このようなモワレの目立つ画像では、Boxサンプルと比べてかなり画質が向上するようです。
Vectexと組み合わせることで、より画質の向上が期待できそうです。
ただし、VectexではSATを正常に処理することができていません。
理由はよくわからないのですが、SATのコードはミップマップの計算時にのみ有効で、通常のレンダリングでテクスチャ画像からサンプリングを行うときにはうまく機能しないようです。
通常のビットマップ画像を使っている場合でも、SamplingパネルでMipmap機能をOFFにすると「Filter:」ドロップダウンメニューでSATが選択できなくなります。
pic100216_05.jpg

Vectexでタイルキャッシュを有効にした場合は、通常のミップマップ計算は使用せずにすべてVectexの機能で処理するため、SATを使用すると上の画像のように色がおかしなことになってしまいます。

○バックグラウンドレンダリング
Blender2.49まではレンダリングを実行している間はButtons Windowのパネルなどは、一切操作ができなくなっていました。
しかしBlenser2.5ではレンダリングを行っている間でも通常の操作を行うことができます。
しかも、マテリアルなどの設定を変えると、その変更がリアルタイムにレンダリングに反映されます。
pic100216_06.jpg

これはこれで面白いのですが、レンダリングに非常に時間のかかるシーンをレンダリングする場合は、レンダリングの途中で不用意に設定を変えてしまわないように注意が必要です。

そして、プログラミングをする側の視点からすると、通常のマルチスレッドレンダリングでのスレッド間の競合以外に、さらに複雑な要素が加わることになります。
Blender2.49でのVectexではパネル上でBase Colorなどを変更した場合、画像のreloadを行うのと同じ処理で対処していました。
reloadを行うと、ファイルから画像を読み込み直す処理が発生します。
この際、QtSVGのバックエンドレンダラをメモリから開放する処理が必要になるのですが、もし別のスレッドでバックエンドレンダラが使用されている間にこれを実行してしまうと、致命的なことになります。

実際、Blender2.49で使用していたソースコードをそのまま使用してレンダリング中にVector Imageパネルの操作を行うと、その瞬間にBlenderがクラッシュしてしまいました。
そのため、Vector Imageパネルの操作を行ったときの処理を変更し、reloadのようにファイルの読み込みが起こらないようにしました。
これである程度はクラッシュを回避できるようになったのですが、Imageパネルにあるreloadボタンを押すと、結局は同じことになります。

色々とソースコードを修正してみて、最終的には
1.バックエンドのレンダリングを行う処理に入る直前に、QtSVGバックエンドが使用中であるというフラグを立てる。
2.ImBufの開放命令が呼ばれた場合、QtSVGバックエンドを使用中のフラグが立っていたら、その場では開放処理を行わず、後でImBufを開放する必要があるというフラグを立てる。
3.バックエンドのレンダリングを行う処理から抜けたら、ImBufの開放をする必要があるかフラグを確認し、必要なら開放を行う。
という形にしてみました。

これで、Vectex機能を使ったシーンをレンダリング中にプロパティの操作を行うとクラッシュするという問題はほぼ克服できたように思います。
(まだ若干不安がある部分もありますが、意図的にreloadボタンを連打したりしなければ大丈夫...だと思います。)
pic100216_07.jpg

もう少し早く公開できると思っていたのですが、色々と問題が起こって修正に時間がかかりました。
ブログの記事としてソースコードの解説を進める予定だったのですが、現在のところ自分の書いているソースコードが二転三転して安定しない状況ですので、もう少し先送りすることになると思います。
とりあえず、次はなるべく早くノードシステムへの対応を行いたいと思っています。
posted by mato at 01:01| Comment(0) | Blender Vectex | このブログの読者になる | 更新情報をチェックする

2009年11月29日

イメージライブラリ(ImBuf)への統合

前回の更新からだいぶ時間がたってしまいましたが、この間ずっとvectexをBlenderのイメージライブラリに組み込み直す作業を行っていました。
少し前にBlender2.5 Alpha 0の公開がありましたが、こちらは相変わらずのBlender 2.49bベースとなります。

Linux 64bit

Linux 32bit

Windows 32bit


ソースファイルのパッチ (Blender2.49.2_Vectex_QtSVG_patch.zip)


vectexをイメージライブラリに組み込むことで以前のバージョンと比べて何が変わったのかというと、SVGファイルを開くための操作がPNG、Jpegなどの通常の画像ファイルを開くのと同じになったということです。

これだけだと何のためにこのように変更したのかよくわからないと思いますが、今回の修正でこれまでできなかったことが色々とできるようになりました。
今回は、その辺についての解説をしてみたいと思います。このため今回はプログラムのソースコードの中身の解説はありません。
ソースコードの変更内容については、今後Blender2.5ベースのソースコードに移植していく過程で少しずつ記事にしていこうと思っています。

SVGファイルを開く操作については、前回の更新のものまではTextureパネルで「Vectex」を選択し、表示されるパネルでファイル選択ボタンを押すという形になっていました。
今回のバージョンでも同じように、Textureパネルで「Image」を選択してイメージテクスチャとしてSVGファイルを開くことができます。
pic091129_02.jpg

Blenderには画像ファイルを開く時にサムネール表示でファイルを選択できる機能があり、ファイル選択ボタンをマウスクリックする際にキーボードの「Ctrl」キーを押すことでイメージセレクタが開きます。
今回はこのイメージセレクタでのSVGファイル表示にも対応しています。
ちなみに下の画像で表示しているのはUbuntuのアイコンを保存しているディレクトリを開いている様子です。
UbuntuをはじめとしたLinuxではデスクトップで表示されるアイコンにSVGファイルが使用できるようになっていて、SVGファイルで作成されている多数のアイコンが標準でインストールされています。
もし興味のある方は一度システムのアイコンディレクトリ(/user/share/icons/ など)をのぞいてみてください。
pic091129_03.jpg

このようにSVGファイルをイメージテクスチャとして開くと、レンダリング時にSVGファイルがテクスチャとして適用されます。
SVGファイルをテクスチャとして使用する場合の操作については、これまでのバージョンとほとんど同じです。

●新規に追加されたボタン
イメージテクスチャを作成すると、Imageパネルの横に「Vectex」パネルが表示されます。
今回、新しく追加した機能として固定サイズのビットマップ画像としてSVGファイルを使用できるようにしました。
「UseTileCache」をオンにするとこれまで通り通常のVectexとして解像度計算を行ってタイル画像を作成しますが、このボタンをオフにするとタイル画像の作成を行わなくなり、PNG、Jpegなどの画像ファイルのように固定サイズのビットマップとして使用できるようになります。
pic091129_05.jpg pic091129_06.jpg

このとき作成される画像データのサイズはデフォルトではSVGファイル内に記述されたサイズを使用しますが、これも今回追加した「UseCustmoSize」というボタンをオンにすることで、その横にある「SizeX」「SizeY」に指定した任意のサイズに変更することができます。
pic091129_07.jpg pic091129_08.jpg

●UV/Image EditorでのSVG画像表示
今回、UV/Image EditorでもSVGファイルを表示できるようにソースコードを修正しています。
もともとBlenderのUV/Image Editorには、UV座標にメッシュを展開した画像をSVG画像として保存する機能がありますので、その画像をUV編集時の下絵としてSVGファイルで読み込めたら便利なのではと思っていました。
pic091129_09.jpg pic091129_27.jpg

「UseTileCache」「UseCustomSize」ボタンは、UV/Image Editorの表示にも反映されます。
「UseTileCache」がオンの時は、マウスホイールでのズームのレベルに合わせてタイル画像が作成され、ズームの限界一杯になるまで最適な解像度の絵が表示されます。
「UseTileCache」がオフの時は、PNG、Jpegなどの画像の場合と同様にビットマップでの表示となり、ズームするとピクセルが四角形として表示されます。
このとき、「UseCustomSize」が有効なら指定した解像度のビットマップとして表示されます。
pic091129_10.jpg pic091129_11.jpg

UV/Image Editorでは画像を表示するだけでなく、ペイント機能を使って絵を描くこともできます。
SVGファイルを表示しているときにペイントしたらどうなるのか、ちょっと疑問に思われるかもしれません。
結果から言うと「UseTileCache」ボタンがオンのときにはペイントを行うことはできませんが、「UseTileCache」ボタンをオフにしていればペイントを行うことができます。
pic091129_12.jpg pic091129_13.jpg

ペイントした結果をPNG、Jpegなどのビットマップ画像として保存することができますが、SVGファイルとして保存することはできません。
ビットマップ画像として保存する場合、「UseCustomSize」でサイズを指定していればその解像度で保存されます。
注意が必要なのは、Vectexパネルで「UseCustomSize」をオン/オフしたり、画像サイズを変更したり、Base Colorを変更したり...というような操作をするとペイントした結果が破棄されてしまうことです。
もしSVG画像を元にしてにペイント画像を作成したい場合は、まずPNG、Jpegなどの画像データとして保存してからペイント操作を行うのが安全です。

●3D Viewでのテクスチャ表示
SVGファイルをビットマップ画像として使用する機能を追加することで、3D Viewでのテクスチャ表示にSVGファイルを表示できるようになりました。
このビットマップ画像は、GLSLマテリアル表示を行う場合にも使用されます。
pic091129_14.jpg pic091129_15.jpg

ただ、この3D Viewでのテクスチャ表示にはVectexのタイルキャッシュの機能は反映されません。
「UseTileCache」ボタンがオン/オフのどちらになっていても、表示される内容は同じです。
「UseCustomSize」ボタンの機能は有効なので、3D Viewでの表示で解像度が不足してピクセル表示が目立つようであれば、Vectexパネルで画像サイズを大きく変更することでテクスチャ表示を改善することができます。
pic091129_16.jpg pic091129_17.jpg

●3D Viewでの下絵としてSVG画像を表示

3D View表示ではモデリングを行う際に、下絵として画像ファイルを背景に表示することができます。
今回、SVGファイルを下絵として使用できるようにしました。
pic091129_18.jpg

「UseTileCache」「UseCustomSize」ボタンを使用したときのビュー上での表示の違いはUV/Image Editorと同じです。
3D Viewの下絵表示がUV/Image Editorと若干違うのは、最大ズームレベルがより高い状態にまで拡大できることです。
試してみたところVectexのタイル画像作成機能を最大ズームレベルまで行うと、メモリの限界に到達してしまうのか、Blenderがクラッシュしてしまいました。
クラッシュするズームレベルはLinux、WindowsなどのOSの違い、64bit、32bitの違いなどによって若干違うようですが、最大で2の20乗(画像サイズ 1048576 x 1048576 相当)までに制限することにしました。

もし、この限界近くまでズームするような場合、マウス操作に対する反応がかなり悪くなる可能性があります。
これは、Vectexの作成するタイル画像の枚数が非常に多くなるためです。
メモリの使用量がVectexパネルで指定されている「Mem Max」の値を超えていると、作成済みのタイル画像を削除する処理も加わるため、さらに負荷が重くなります。
もし、メモリに余裕があるなら「Mem Max」の値を大きくする(「0」を指定した場合は無制限)ことで、下絵表示を行っている3D ViewやUV/Image Editorでの操作をより快適に行うことができるようになると思います。

●ノードエディタ
SVGファイルを開く方法はここまでに書いたもの以外にもまだあり、ノードエディタとシークエンスエディタでも使用することができます。
ノードエディタには、マテリアルノード、コンポジットノード、テクスチャノードの3つの種類があります。
このうち、ノードエディタ上でイメージノードを使う際に、SVGファイルを使用することができます。
イメージノードを使うことができるのはコンポジットノードとテクスチャノードのみで、マテリアルノードでは使用できません。
pic091129_28.jpg

また、イメージノードを使う以外にSVGファイルを使用したイメージテクスチャをテクスチャノードとして使用することもできます。
テクスチャノードはマテリアルノード、コンポジットノード、テクスチャノードのすべてで使用可能です。
pic091129_29.jpg

ちょっと分かりにくいかもしれませんが、イメージノードとしてSVGファイルを使用した場合と、テクスチャノードとしてSVGファイルを使用した場合とでは、Vectexの機能のうち使えるものと使えないものとが違ってきます。

○マテリアルノード
マテリアルノードではイメージノードは作成できないため、テクスチャノードのみとなります。
あらかじめイメージテクスチャを作成しておき、SVGファイルを開いておきます。
ノードエディタのメニューから「Add」-「Input」-「Texture」を実行してテクスチャノードを作成し、作成しておいたSVGファイルのテクスチャを選択します。
同じようにノードエディタのメニューから「Add」-「Input」-「Geometry」を実行してジオメトリノードを作成し、出力の部分でGlobal/Local/View/Orco/UVのうちいずれかのマッピング座標系とテクスチャノードの「Normal」の入力を接続します。
このようにしてSVGファイルを使用する場合、イメージテクスチャのVectexパネルのボタンを操作することでタイルキャッシュのオン/オフやビットマップ画像として使用する場合のサイズ変更などを行うことが可能です。
pic091129_19.jpg

○テクスチャノード
テクスチャノードでは、イメージノードとテクスチャノードの両方を使用できます。
SVGファイルを使用したイメージテクスチャをテクスチャノードで使用する場合は、Vectexのタイルキャッシュ機能を使用することができます。
また、スケールノードを使用して絵の一部分を拡大すると、その拡大率に合ったレンダリング結果を得ることができます。
一方、テクスチャノードの中でイメージノードとしてSVGファイルを使用する場合は、Vectexのタイルキャッシュは効果がありません。
イメージノードのビットマップのサイズを「UseCustomSize」で変更することは可能です。
pic091129_20.jpg pic091129_21.jpg

○コンポジットノード
コンポジットノードではイメージノードとテクスチャノードの両方を使用できます。
ただし、コンポジットノードではVectexのタイルキャッシュは効果がありません。
テクスチャノードを使用するとレンダリング画面一杯に絵が引き伸ばされる状態になります。
もし、解像度が足りずにピクセルの四角形が目立つようなら、「UseCustomSize」を有効にしてビットマップの解像度を上げてください。
イメージノードを使用すると、レンダリング画面の中央にビットマップの解像度で絵が表示される状態になります。
この場合も、表示される絵が小さすぎる場合は「UseCustomSize」を有効にしてSVGファイルのイメージサイズを大きくしてください。
pic091129_22.jpg pic091129_23.jpg

●シークエンスエディタ
シークエンスエディタでは、イメージストリップとしてSVGファイルを使用することができます。
シークエンスエディタのメニューから「Add」-「Images」を実行することで、イメージストリップを作成できます。
ちょっと注意が必要なのは、これまでに説明したすべての方法についてはSVGファイルの設定を変更する際に、Buttons Windowのモードが「Shading(F5)」「Texture Buttons(F6)」の状態で表示されるVectexパネルを使用していましたが、シークエンスエディタで開いた場合にはこの方法ではイメージのデータにアクセスできないということです。
シークエンスエディタでは代わりにButtons Windowのモードを「Shene(F10)」「Sequence Buttons」の状態にしたときにシークエンスエディタ専用のVextexパネルが表示されます。
見ていただくとわかりますが、イメージテクスチャで表示されるVectexパネルと比べて使用できる機能が少なくなっています。
pic091129_24.jpg

シークエンスエディタでのVectexの機能は、基本的にはノードエディタの場合のコンポジットノードと同じような感じで、ビットマップデータとしてSVGファイルのサイズが変更できる程度のものになっています。
ただし、実験的にトランスフォームエフェクトを使用したときにだけタイルキャッシュ機能を使えるようにしてみました。
pic091129_25.jpg

なぜ実験的なのかといえば、タイルキャッシュが使えるのはある条件が満たされている場合に限られるためです。
その条件というのは、以下のようなものです。
トランスフォームエフェクトはSVGファイルのイメージストリップに対して直接適用する必要があります。
イメージストリップに何らかのエフェクトを適用した結果に対してトランスフォームエフェクトを適用した場合、タイルキャッシュは無効になります。
シークエンスエディタではトランスフォームエフェクトを含めてエフェクトをかけた結果に対してさらにエフェクトをかけるという操作を何重にも繰り返すことが可能ですが、タイルキャッシュを使えるのはSVGファイルのイメージストリップに直接適用されたトランスフォームエフェクトのみに限定されます。

●その他
今回の更新で追加された機能は、以上のような感じです。
そして、これは機能の追加とは違った話になりますが、今回の更新ではSVGファイルの描画に使用しているライブラリQtSVGのプログラミング上での扱いが変わっています。
具体的には、ダイナミックローディングという方法を使うことで、もしQtがインストールされていないPC上でBlenderを起動した場合でも、Vectexの機能が使用できなくなるだけで通常のBlenderとして使うことができるようにしています。

ただし、QtのようにC++で書かれているライブラリを直接C言語で書かれたBlenderでダイナミックに読み込むことはできません。
そのため、VectexのソースコードのうちQtに依存する部分だけを分離して、Blenderの実行ファイルの置かれている場所にある「Plugins」フォルダの中に置いてあります。
Linuxではlibqtsvg_vectex.so、Windowsではqtsvg_vectex.dllというファイル名になっています。
pic091129_26.jpg
posted by mato at 21:49| Comment(13) | Blender Vectex | このブログの読者になる | 更新情報をチェックする

2009年10月07日

メモリリーク

今回の更新はバグフィックスのみです。
修正したバグはメモリリークが起こっていたことです。

実行ファイルはこちらになります。

Linux 64bit


Linux 32bit


Windows 32bit


ソースファイルのパッチ(Blender2.49.2_Vectex_QtSVG_patch.zip)

AGGバージョンも更新しています。
実行ファイルは以前の記事からダウンロード可能です。
AGGバージョンのソースファイルのパッチ(Blender_modified_patch091005.zip)


以下、今回の修正内容について詳しく説明します。
元々のプラグインのvectexでは、メモリの管理について以下のように行っています。
vectexは大量のタイル画像を作成しますが、それらのタイル画像はTile構造体の*imageというポインタでアクセスできるようになっています。
typedef struct Tile
{
    unsigned char *image;
    unsigned int   age;
} Tile;
そしてそのTile構造体にはInstance構造体から*tile_setというポインタでアクセスします。
typedef struct Instance
{
    void         *backend_data;
    int           tile_set_max_power;
    Tile         *tile_set;
    int           tile_memory;
    unsigned int  timestamp;
    unsigned char current_base_color[4];
    char          current_file_name[64];
} Instance;
Instance構造体へのアクセスのために、PluginのCast構造体に*instance_dataというポインタを登録しています。
typedef struct Cast
{
    int           enable;
    int           mipmap;
    int           interpol;
    /*int           usealpha;*/
    int           label_dummy0;
    int           tex_level;
    int           mem_max;
    int           mem;
    int           label_dummy1;
    unsigned char base_color[4];
    int           label_dummy2;
    char          file_name[64];
    int           label_dummy3;
    void         *instance_data;
} Cast;
このブログを始めてすぐのころにBlenderのプラグインの仕組みを調べていたときには気づかなかったのですが、通常Cast構造体に登録されるのはPluginパネルに表示されるボタンの状態を保持するためのデータであって、大量の画像へのポインタを保持するInstance構造体へのポインタのようなものを登録するのはかなり特殊な使い方と考えていいようです。

BlenderのプラグインAPIはこのような使い方を想定して作られていないので、Blenderの終了時などにプラグインを使用しているテクスチャが削除される処理が行われるとき、Cast構造体自体が削除されてもそこに登録されたポインタが指す実体については削除されないことになります。

このような理由からオリジナルのvectexではBlenderの終了またはプロジェクトを閉じる処理が行われたとき、作成したタイル画像のデータ、そしてそれを管理するInstance構造体などのデータが使用しているメモリ領域がきちんと解放されずにメモリリークを起こしています。

現在のOSではアプリケーションの終了時にはそのプロセスに割り当てられたメモリ領域全体が破棄されるような仕組みになっていて、実際にはこのメモリリークが大きな問題になることはなさそうです。
ただし、アプリケーションを終了せずにプロジェクトを閉じる操作を何度も続けると問題がおこるかもしれません。
具体的には、vectexを使用してレンダリングを実行し、Blenderを終了しないまま新規プロジェクトを作成し、新しいプロジェクトでvectexを使用してレンダリングを実行、新規プロジェクトを作成...というように操作を続けていくとメモリが不足する可能性があります。

では、vectex内臓版のBlenderではこのあたりのことがどうなっているのかというと、
作成されるタイル画像は、VtexTile構造体の*imageポインタでアクセスされます。
typedef struct VtexTile
{
    unsigned char *image;
    unsigned int   age;
    float pad;
} VtexTile;
VtexTile構造体にはVtexInstance構造体の*tile_setポインタでアクセスされます。
typedef struct VtexInstance
{
    void         *backend_data;
    int           tile_set_max_power;
    int           tile_memory;
    unsigned int  timestamp;
    unsigned char current_base_color[4];
    char          current_file_name[160];
    short imaflag;
    short vtex_imaflag;
    float pad;
    struct VtexTile         *tile_set;
} VtexInstance;
さらにVtexInstance構造体にはBlenderのテクスチャのデータ全般を管理しているTex構造体に追加した*vtex_instance_dataからアクセスできるようになっています。
typedef struct Tex {
...   
    /* vectex */
    float vtex_resolution_scale;
    int vtex_enable, vtex_mipmap, vtex_interpol, vtex_tex_level, vtex_mem_max, vtex_mem;
    unsigned char vtex_base_color[4];
    char vtex_file_name[160];
    short vtex_imaflag;
    short vtex_version;
    char pad1[4];
   
    struct PackedFile * vtex_packedfile;
    struct VtexInstance *vtex_instance_data;
...
} Tex;
Blenderの終了時には、テクスチャのデータを保持するTex構造体は、blender/source/blender/blenkernel/intern/texuture.c (line:417)にあるfree_texture()という関数でメモリの解放を行っています。

Tex構造体に追加したポインタ*vtex_instance_dataの実体もここでメモリの解放を行う必要があります...が、これまでメモリの解放処理を書かないまま放置してありました。
このため、vectex内臓版Blenderでもアプリケーション終了時やプロジェクトを閉じた時に、オリジナルのプラグインとまったく同じようにメモリリークを起こしていました。

本来ならTex構造体にポインタ*vtex_instance_dataを追加した時点で気づいていなければいけなかったのですが、今頃になって気づきました。
プラグインと違ってBlender自体のソースコードを自由に変更できる状況にありながら、数ヶ月もの間メモリリークを放置していたとは、なんとも情けない話です...。


今回の更新でのソースコードの修正内容です。
前回からの修正内容(changes091006.zip)

まず、free_texture()関数にメモリの解放の処理を書く必要があります。
blender/source/blender/blenkernel/intern/texuture.c (line:417)
void free_texture(Tex *tex)
{
    free_plugin_tex(tex->plugin);
    if(tex->coba) MEM_freeN(tex->coba);
    if(tex->env) BKE_free_envmap(tex->env);
    if(tex->vtex_instance_data) vtex_destroy_instance(tex);
    BKE_previewimg_free(&tex->preview);
    BKE_icon_delete((struct ID*)tex);
    tex->id.icon_id = 0;
   
    if(tex->nodetree) {
        ntreeFreeTree(tex->nodetree);
        MEM_freeN(tex->nodetree);
    }
}
ここで使用しているvtex_destroy_instance()という関数はこれまでvectex()関数と同じblender/source/render/intern/source/texuture.cに置いていましたが、blender/source/blender/blenkernelという全く別のディレクトリにあるファイルから参照できるようにする必要があります。
しかし、そもそも現状ではvtex_destroy_instance()関数は、外部のファイルから使用できるようにするためにプロトタイプ宣言をヘッダファイルで公開していません。
blender/source/blender/render/intern/include/texture.hというヘッダファイルにこの関数のプロトタイプ宣言を書いて、blender/source/blender/blenkernel/texuture.cから参照できるようにすることもできますが、関数の用途と配置について考えるとむしろvtex_destroy_instance()関数そのものを.../blenkernel/texture.cの方に移してそれを.../render/intern/source/texture.cの方から使用するというようにした方がいいようです。

実際にこの関数を移動することを考えた場合、この関数で使用しているいくつかの関数も同じようにファイルを移動させる必要がでてきます。
vtex_destroy_tile_set()関数と、その関数で使われているvtex_get_base_index()関数です。

vtex_destroy_instance()関数では、これ以外にもvtex_destroy_backend()関数も使われていますが、こちらはもともとblender/source/vectex/vectex.hで公開されているので、そのヘッダファイルをインクルードするだけで使用できます。

.../blendkernel/texture.cに移動したので、.../render/intern/source/texture.cからはこれらの関数は削除しました。
これらの修正は移動のみの修正のため、ソースコードの引用については省略します。

移動した関数のプロトタイプ宣言をヘッダファイルに追加します。
blender/source/blender/blenkernel/BKE_texture.h
...
struct VtexInstance;
...
...
int vtex_get_base_index(int power);
void vtex_destroy_instance(struct Tex *tex);
void vtex_destroy_tile_set(struct VtexInstance *instance);

...
移動した関数をコンパイル時に正しく認識できるように、SConsの設定ファイルSConscriptファイルの内容を修正します。
blender/source/blender/blenkernel/SConscript
...
if env['WITH_BF_VECTEX']:
    incs += ' ../vectex'


env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [65, 20] )
このように一つの関数を複数の場所のファイルから参照できるようにすると、インクルードファイルの位置だけでなく、コンパイル後に作成されるライブラリの有線順位priorityについても変更が必要になることがあります。
今回は、blender/source/blender/vectexディレクトリのSConscriptファイルのpriorityの数値をblender/source/blender/blenkernelのSConscriptと同じになるように修正しました。
もともとはblender/source/blender/renderのSConscriptに合わせていましたが、そのままではWindowsのmingwでのコンパイルでエラーが出てしまったため、より有線順位が高いと思われるblenkernelの方に合わせることにしました。

blender/source/blender/vectex/SConscript
...
env.BlenderLib ( libname='bf_vectex',
        sources=sources, includes=Split(incs),
        defines=Split(defs),
        libtype=['core','player'], priority = [65, 20], compileflags = Split(cflags))

今回の修正内容はこれだけです。

この修正を行うにあたってLinuxでメモリリークの有無をしらべることのできるツールを探し、Valgrindというものを使ってみました。
このツールはGUIのないコマンドラインで使用するタイプのものですが、メモリリークを調べるだけという簡単な用途で使うなら、使い方はそれほど難しくありません。

通常の操作で

myprog arg1 arg2

というようにコマンドラインで使用するプログラムを

valgrind --leak-check=yes myprog arg1 arg2

というようにするだけで、端末画面にエラーメッセージが表示されます。
動作スピードがかなり遅くなりますが、BlenderのようなGUIプログラムでも通常と同じようにプログラムが起動し、普通に操作することができます。

ただし、Blederを調べようとすると大量のエラーメッセージが表示されて、これ以上メッセージを表示しないというように言われてしまいます。

valgrind --leak-check=yes --error-limit=no ./blender

というように--error-limit=noというオプションを付けることで、この問題を回避できるようです。
今回の修正前の状態では、valgrindの出力に以下の様にvectexのメモリリークが表示されました。
...
==8900== 348,284 bytes in 5 blocks are possibly lost in loss record 369 of 372
==8900==    at 0x4C278AE: malloc (vg_replace_malloc.c:207)
==8900==    by 0x14DCD8A: MEM_mallocN (mallocn.c:258)
==8900==    by 0xAF43F9: vtex_create_instance (texture.c:920)
==8900==    by 0xAF5D2E: vtex_check_instance (texture.c:1286)
==8900==    by 0xAF5FEB: vectex (texture.c:1344)
==8900==    by 0xAFE27D: multitex (texture.c:3155)
==8900==    by 0xB00D35: do_material_tex (texture.c:3686)
==8900==    by 0xB41188: shade_lamp_loop (shadeoutput.c:1566)
==8900==    by 0xB6F42F: shade_material_loop (shadeinput.c:93)
==8900==    by 0xB6FAE6: shade_input_do_shade (shadeinput.c:154)
==8900==    by 0xB6B9C4: shade_tra_samples (zbuf.c:3889)
==8900==    by 0xB6CC5F: zbuffer_transp_shade (zbuf.c:4191)
...

今回の修正後、vectexのメモリリークの表示はなくなったようです。
(起動後の操作によって出力の内容も変わるので、操作内容によっては別の結果が出る可能性があります。)
posted by mato at 00:09| Comment(2) | Blender Vectex | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。