試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

WOLF RPG エディターのバージョン2.10で作成された作品をWineで3Dモードで動かしたときに文字描画が崩れる現象について(2014年2月末時点)

(2015/12/28)本記事は「WineでWOLF RPG エディター 2.10作品が3Dモード時に文字化けする問題と対処」へ移動した。

(2015/2/2)この問題については「WOLF RPG エディター 2.10作品が3Dモード時にWineで文字化けする問題の邪道な対処」を参照。

以下、以前の内容となる。

2013年12月頃、WOLF RPG エディターのバージョン2.10で制作された作品をダウンロードしてWineで動かしてみたところ、文字の描画が所々おかしくなっているのに気付いた。

  1. 不具合について
  2. バグ報告とその後の流れ
  3. DXライブラリ関係の問題について
  4. Wineにとっての問題点や対策について
    1. 他の影響を受けるプログラムなどについて
    2. WOLF RPG エディター(2.10)作品についての今後の対策

不具合について

この現象は3Dモード(GPU描画モード)での描画時にのみ起こり、ソフトウェアモード(ソフトウェア描画モード)では起こらない。
文字の描画は最初プログラムを開始したあたりでは幾つかの文字だけが崩れている状態だが、しばらく色々なメッセージなどを表示している内に大部分が壊れた描画になってしまう。

作品依存かとも思ったが、バージョン2.10に付属するサンプルゲームで試してみても同様の現象が起きたため、このバージョン(のGame.exe)に固有な不具合と判断した。
winetricksDirect3D関係の設定変更や一部DLLのネイティブ版への置き換えも試したが変化はなかった。
古いバージョンのWineを試したところ、バージョン1.3.5までのバージョンで問題が起こらないように見えたが、これは3Dモードが正しく初期化できずにソフトウェア描画になっているためで動作も遅かった。エディタからサンプルゲームのテストプレイを行うとLog.txt

629:	IDirect3D9Ex オブジェクトを取得します.... 成功
758:	IDirect3DDevice9Ex オブジェクトを取得します.... Direct3DDevice9Ex の作成に失敗しました
854:	IDirect3DDevice9Ex オブジェクトを取得します.... Direct3DDevice9Ex の作成に失敗しました
951:	IDirect3DDevice9Ex オブジェクトを取得します.... Direct3DDevice9Ex の作成に失敗しました
1055:	IDirect3DDevice9Ex オブジェクトを取得します.... Direct3DDevice9Ex の作成に失敗しました

といった出力があることからもそれが分かる。
どのタイミングから3Dモードが正しく動作するかを調べたところ、バージョン1.3.5と1.3.6の間の「d3d9: Partially implement IDirect3D9Ex::CreateDeviceEx().」という(つじつまの合う)結果となり、結局「3Dモードが正しく動作する最初のバージョン(のWine)からはずっと不具合が発生する」と分かっただけだった。

バグ報告とその後の流れ

というわけで、この件についてのバグ報告を12月末に行った。その際

  • WOLF RPG エディターはDXライブラリを使用している
  • 同ライブラリのソースは公開されている

ということを添えて記述した。
これに対して1月末にSagawa氏によって「DXライブラリを直接用いた小さなテストプログラムで現象を再現できた」という旨のコメントが出され、その数日後に突然

  • 不具合の原因はDXライブラリの中にあり、同ライブラリの最新バージョン(3.11d)で修正された
  • WOLF RPG エディターの将来のバージョンでDXライブラリのバージョン3.11d以上を用いたバージョンが利用可能になったらそれを用いて動作テストを行ってほしい

という旨のコメントが出された。

DXライブラリ関係の問題について

詳細についてはそこでは語られなかったが、突然このような流れになったことからDXライブラリの作者と何かやりとりが行われていた可能性があると思い、同ライブラリの作者のサイトを探してみた。その結果それが確認できた。
同氏によるとバージョン2.10のWOLF RPG エディター(のGame.exe)に使われているバージョン3.10fのDXライブラリ(先述のLog.txtの冒頭付近にDXライブラリのバージョンが出力されるので確認が可能)について「Direct3Dの仕様上保証されていない動作に依存している」部分があるということで、具体的には「IDirect3DDevice9::UpdateTexture()についてIDirect3DTexture9::LockRect()で作成したダーティ領域(と呼ばれる領域)のみをコピーすることをDXライブラリ側は期待しているが、仕様上ダーティ領域のみをコピーすることは保証されていない」として指摘・報告している。
この不具合は二人のやりとりの数日前に別の方によって報告された不具合の関係で作者が開発(暫定)バージョンで修正済みで、上記の「報告」の翌日に公開されたバージョン3.11dでも修正済みとのことだった。Sagawa氏によるとそのバージョン3.11dではテストプログラムで描画が正常に行われることが確認できており、また、同氏が問題点の対処として提案したIDirect3DDevice9::UpdateSurface()を用いた使用メモリ節約版でも正常な動作を確認したということだった。

Wineにとっての問題点や対策について

他の影響を受けるプログラムなどについて
DXライブラリはWOLF RPG エディターなどのこれを使用するアプリケーションからビルド時に静的リンクされる(ライブラリ部分がプログラム本体と分離されずに取り込まれる)ため、最新バージョンのライブラリで修正されたといってもこの不具合の影響を受けるバージョンのDXライブラリを用いて(取り込んで)作成されたプログラムはWineで動かすと不具合が出るのを避けられない(なのでSagawa氏は「修正された後の将来のバージョンでテストを」とコメントしている)。WOLF RPG エディターは不具合回避としてソフトウェア描画モードが利用できるのでまだよいかもしれないが、DXライブラリにはソフトウェア描画機能無し版も存在するので、そちらの該当バージョンを使って作られたものに当たった場合はどうしようもなくなる。
今回の件についてはDXライブラリのバグという形なのでWineに欠陥があるというわけではないが、多くのWindowsが「ダーティ領域のみをコピーする」という動作をしているのであれば、それが保証されていない動作だとしても、例えばWineレジストリ設定の値によってそのような動作をするようにWineを変更するいったやり方は考えられるかもしれない。ただ、仮にそれが技術的に可能であったとしてもWineのプロジェクト側がそのような動作をするコードを受け入れるかどうかは分からない。

WOLF RPG エディター(2.10)作品についての今後の対策
WOLF RPG エディターのバージョン2.10で作られた作品についてはバージョン2.10の後にDXライブラリのバージョンを3.11d以上にして公開される最初のバージョンが将来公開されるまではソフトウェアモードを利用するしかない。それが公開されたら既存のGame.exeに上書きして動かすことで不具合の解消ができることを期待するが、そのバージョンに上がる際にWOLF RPG エディター内に仕様変更があった場合、バージョン2.10で作られた作品が正常に動かないかもしれない。
WOLF RPG エディターの公式サイトにある「バグ報告スレッド 11」には今回の件についてと「DXライブラリを最新にして、かつ仕様変更のないバグ修正バージョンのリリースをしてほしい」旨を2月上旬に書き込んではいるものの、WOLF RPG エディターの作者が目を通したかどうかは不明で、目を通していたとしてもそのようなバージョンが近い内に公開されるという保証はない。WOLF RPG エディターの過去の「DXライブラリのバージョンの更新」は慎重で、作者のTwitter上の発言によると、作者の環境でバージョンを試しに上げた結果不具合が出て新バージョンの採用が先送りになったこともある。

いずれにしても、今回の件ではSagawa氏の活躍がなければ何も分からないままだった可能性が高く、改めて感謝する。

UbuntuのパッケージとMozilla版それぞれのFirefoxのビルド時のオプションと快適さなどについて(バージョン27時点)

UbuntuのパッケージとMozilla版のビルド時のオプションの比較

Ubuntuのパッケージのバージョン27のビルド時のオプション

Ubuntuのディストリのパッケージとして提供されているFirefoxのビルド時の最適化オプションがふと気になったので、about:buildconfigで調べてみた。

Ubuntuのパッケージのバージョン27のオプション(x86_64版)
項目
GCCのバージョン4.8.1-10ubuntu8
gccのオプション-Wall -Wpointer-arith -Wdeclaration-after-statement -Werror=return-type -Wtype-limits -Wempty-body -Wsign-compare -Wno-unused -Wcast-align -std=gnu99 -fgnu89-inline -fno-strict-aliasing -fno-math-errno -pthread -pipe -DNDEBUG -DTRIMMED -g -Os -freorder-blocks -fomit-frame-pointer
g++のオプション-Wall -Wpointer-arith -Woverloaded-virtual -Werror=return-type -Wtype-limits -Wempty-body -Wsign-compare -Wno-invalid-offsetof -Wcast-align -fno-exceptions -fno-strict-aliasing -fno-rtti -fno-exceptions -fno-math-errno -std=gnu++0x -pthread -pipe -DNDEBUG -DTRIMMED -g -Os -freorder-blocks -fomit-frame-pointer
configureスクリプトのオプション--host=x86_64-linux-gnu --prefix=/usr --libexecdir=/usr/lib/firefox --with-l10n-base=/build/buildd/firefox-27.0+build1/./l10n --srcdir=/build/buildd/firefox-27.0+build1/. --disable-install-strip --disable-updater --enable-application=browser --enable-startup-notification --with-distribution-id=com.ubuntu --enable-optimize --enable-tests --enable-crashreporter --with-branding=browser/branding/official --disable-gnomevfs --enable-gio --enable-update-channel=release --disable-debug --disable-elf-hack

Mozilla版のバージョン27のビルド時のオプション

ftp.mozilla.org/pub/mozilla.org/mozilla.org/firefox/releases/27.0/linux-x86_64/ja/
にあるバージョン27のx86_64版バイナリについて、ビルド時のオプションを同様に調べてみた。

Mozilla版のバージョン27のオプション(x86_64版)
項目
GCCのバージョン4.7.3
gccのオプション-Wall -Wpointer-arith -Wdeclaration-after-statement -Werror=return-type -Wtype-limits -Wempty-body -Wsign-compare -Wno-unused -Wcast-align -Wno-error=uninitialized -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -std=gnu99 -fgnu89-inline -fno-strict-aliasing -ffunction-sections -fdata-sections -fno-math-errno -pthread -pipe -DNDEBUG -DTRIMMED -g -fprofile-use -fprofile-correction -Wcoverage-mismatch -O3 -fomit-frame-pointer
g++のオプション-Wall -Wpointer-arith -Woverloaded-virtual -Werror=return-type -Wtype-limits -Wempty-body -Wsign-compare -Wno-invalid-offsetof -Wcast-align -Wno-error=uninitialized -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -fno-exceptions -fno-strict-aliasing -fno-rtti -ffunction-sections -fdata-sections -fno-exceptions -fno-math-errno -std=gnu++0x -pthread -pipe -DNDEBUG -DTRIMMED -g -fprofile-use -fprofile-correction -Wcoverage-mismatch -O3 -fomit-frame-pointer
configureスクリプトのオプション--enable-update-channel=release --enable-update-packaging --with-google-api-keyfile=/builds/gapi.data --enable-crashreporter --enable-release --enable-elf-hack --enable-stdcxx-compat --enable-warnings-as-errors --enable-official-branding

最適化オプションの比較

-Osと-O3

GCC-O[数字かs]の最適化オプションの内、Ubuntuのパッケージでは-Os(標準的な最適化オプション-O2の指定から、機械語ファイルのサイズが小さくなるように幾つかのオプションを除いたもの)が用いられているが、Mozilla版ではより最適化レベルの高い-O3オプションが用いられている。

PGO

Mozilla版ではProfile-guided optimization (PGO)と呼ばれる最適化が有効になっているが、Ubuntuのパッケージでは有効になっていない(オプション指定などについては後述)。

体感差

Mozilla版はあまり使ったことがなかったが、今回試しに動かしてみたところ、上記の2つの違いがあったこともあり、動作が軽くなっているのを実感できた。Ubuntuのパッケージが今後これら2つについてMozilla版と同じようにビルドされるようになるまではMozilla版を使うことになりそう。

関連:PGOとこれに関係したGCCのオプション指定について

PGOは「実際にプログラムを動かし、そのときの動かし方にプログラムを最適化する」という手法で、時間と手間がかかる一方で動作速度の向上が図れる。

1回目のビルド

「各ソースファイルのコンパイル時」と「リンク時」の両方に-fprofile-generateオプションを付けることにより、プログラム実行時にプロファイルのファイル群を書き出すよう変更を加える(これを「インストゥルメント」と呼ぶ)。
-fprofile-generate=[出力先]指定でファイルの出力先ディレクトリを指定することもできる(出力先指定なしの場合は各ソースのファイルと同じディレクトリになる)。
MozillaFirefoxのabout:buildconfigでは1回目のビルド時にのみ付く-fprofile-generateオプションは確認できないが、これは2回目のビルド時に付く後述のオプションのみがabout:buildconfigに出るため。

実行

実行ファイルができたら、最適化させたい動かし方でそれを実行する。これにより、自動的にプロファイルのファイル群(*.gcda)が書き出される。最適化させたい動かし方が複数あればその分だけ動かす。
Firefoxを後述の手順でビルドする場合はbuild/pgo/profileserver.pyが自動的に実行される。動かし方をカスタマイズするには、このスクリプトか、これを呼び出す記述を含むtesting/testsuite-targets.mkの「pgo-profile-run」ターゲットを編集する。

2回目のビルド

「各ソースファイルのコンパイル時」と「リンク時」の両方に-fprofile-useオプションを付ける。
-fprofile-use=[出力先]指定で.gcdaファイルの探索ディレクトリを指定することもできる。
マルチスレッドのプログラムではプロファイルのファイルが正しく書き出されないことがあり、それを修正して用いるために-fprofile-correctionオプションも付ける。
プロファイルのファイルが生成された後でソースが修正されたときなど、プロファイルのファイルがソースファイルに正しく対応していない場合にはエラーが発生し、-Wcoverage-mismatchオプションを付けるとエラーで止まる代わりに警告が出るようになるが、それでビルドが通っても最適化の度合いは落ちる。
MozillaFirefoxのabout:buildconfigでは-fprofile-use-fprofile-correctionのオプションが確認でき、PGOによる最適化がされたものであると分かる。

Firefoxのビルド時の手順
  1. ソースの最上位ディレクトリに「ac_add_options --enable-application=browser」を含み「ac_add_options --disable-tests」を含まない.mozconfigを作成
  2. ディレクトリで「make -f client.mk profiledbuild」を実行

以下は余談。
以前試してビルドエラーになったことがあったのでこの機会に試してみたのだが、残念ながら1回目のビルドのlibxul.soのリンクでメモリが不足し、スワップの読み書きがされるだけになって処理が進まなくなったために断念した。ソースの規模も前回ソースからビルドした数年前と比べ非常に大きくなっており、当時(Athlon64を使用)よりCPUが高速になったにも関わらずビルド時間はむしろ長くなっていて、それに加えて新バージョンが出るペースが上がっていることもあり、個人的にはFirefoxをソースからビルドすることは今後しない意向。

関連URL:

日本語の文字列をオーディオデータに変換するOpen JTalkについての追加メモ(2014年1月時点)

新しいバージョン

2013年の年末に

  • hts_engine API
  • Open JTalk
  • MMDAgent "Sample Script"

のバージョンが上がっており、(これまで旧形式でしか利用できなかった)「Mei」の声データについても今回の「MMDAgent "Sample Script"」の新バージョンからOpen JTalk1.06以上/hts_engine API 1.07以上で使われる「.htsvoice」形式のものとなっており、最新のOpen JTalkから利用できるようになっている。

Ubuntu向けパッケージを更新

PPAリポジトリppa:kakurasan/unstable」でOpen JTalk関係のソフトウェアやデータの最新バージョンをUbuntu 13.10向けに公開している。今回は「Mei」の声データ以外はDebianのパッケージをもとにしており、ソースパッケージのdebianディレクトリ以下はDebianのパッケージ(GPL 2以降のライセンス)の改変となる。「Mei」の声データのパッケージの同ディレクトリ以下は自作で、こちらはパブリックドメインとする。

パッケージ名説明アーキテクチャ依存/非依存の種別
libhtsengine1hts_engine APIの共有オブジェクト(Debian/Ubuntuのパッケージのhts_engineコマンドやopen_jtalkコマンドで使用される)依存
libhtsengine-devhts_engine APIを用いたプログラムをビルドする場合に使用
htsenginehts_engineコマンド
open-jtalkopen_jtalkコマンド
open-jtalk-mecab-naist-jdicOpen JTalkで用いられる辞書データ非依存
hts-voice-nitech-jp-atr503-m001「nitech-jp-atr503-m001」の声データ
hts-voice-mei「mei_angry」「mei_bashful」「mei_happy」「mei_normal」「mei_sad」の声データ
今回のバージョンから「Mei」の声データのパッケージは以下のファイル配置となり、全て/usr/share/hts-voice/mei/以下に配置される。

[/]-+-[usr]-+-[share]-+-[hts-voice]-+-[mei]-+-mei_angry.htsvoice
    |       |         |             |       +-mei_bashful.htsvoice
    |       |         |             |       +-mei_happy.htsvoice
    |       |         |             |       +-mei_normal.htsvoice
    |       |         |             |       +-mei_sad.htsvoice

「hts-voice-nitech-jp-atr503-m001」の声データについては2012年の年末から新形式で配布されていたが、今回プログラム側のバージョンを新形式対応のものに上げたのにあわせて最新バージョンを公開した。こちらの配置場所は/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoiceとなる。

.htsvoice形式の声ファイルの指定

Open JTalk1.06以上/hts_engine API 1.07以上では声ファイルは新しい「.htsvoice」形式にのみ対応しているが、この指定(hts_engineコマンドやopen_jtalkコマンド)は-m [.htsvoiceファイルの場所]オプションで行う。

関連記事:

使用したバージョン:

  • hts_engine API 1.08
  • Open JTalk 1.07
  • MMDAgent "Sample Script" 1.4