Visual Studio 2019 Version 16.7以降でディレクトリ生成を伴うシェーダコンパイルに失敗する

8月頃にリリースされた16.7.1から、現在リリースされている16.7.5まで確認済み。
そう、二か月以上Visual Studio 2019でシェーダがコンパイルできない致命的な状態なのである。

再現手順はとても簡単で、DirectX-Graphics-SamplesのVS2019に対応した適当なリビジョン(タグ10.0.19041.0以降あたり)を取得してきて、VS2019でModelViewerをビルドするだけ。シェーダコンパイル時に大体次のような意味不明なエラーを吐く。プロファイルによってはfxcである場合もある。

dxc failed : error code 0x80070459.

詳細な条件は次の通り。

  • hlslファイルをソリューションエクスプローラーに設定して、本来なら正常にコンパイルできる設定にしてある
  • 「ヘッダー ファイル名」または 「オブジェクトファイル名」にディレクトリ生成を伴うパスを指定している
    • 例えば、CompiledShaders\%(Filename).h や $(OutDir)CompiledShaders\%(Filename).cso は該当する
    • 一方、 $(OutDir)%(Filename).cso  はディレクトリを生成しないので該当しない

この原因は以下に報告されている。

Typo in FXC Target in VS 16.7.1 (Developer Community)

要するに、「 FxcOutputs 」と記述されるべき設定が「 _FxcOutputs 」とタイポされているというあまりにもお粗末で下らないバグだ。

幸いにも、プログラムによるバグではなく、設定ファイルによるバグであるため、手元で修正することが出来る。
Visual Studio 2019のインストール場所を変更していない場合、次のファイルをテキストエディタ開く。Community以外の場合も適宜読み替えてほしい。

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\
Microsoft.CppBuild.targets

「 _FxcOutputs 」で検索すると一か所該当する箇所があるので、これを「 FxcOutputs 」に変更し保存する。ただし、管理者権限が必要である。

重複した別の報告(HLSL Shader Compiler fails to create output directory for header files)のリプライによると、Preview版では修正されたようだが、こんな致命的で馬鹿げたバグは即座にhotfixがリリースされるべきだろう。

Asynchronous Capture Screen on Unity 2019.3

Unity 2019.3から、あれこれ自作せずともやっと、ようやく、悲願の非同期スクリーンキャプチャが出来るようになりました。

前提知識として、Unity APIの呼び出しは、一部のAPIを除いてメインスレッドからの呼び出しのみが許可されています。レガシーな同期アプローチは検索すると吐いて捨てるほど出てくるのでそっちを見てください。

スクリーンキャプチャの流れは3工程あり、バージョンアップを経て段階的に非同期可能になっています。

  1. レンダーテクスチャのシステムメモリへの読み戻し
  2. 画像ファイルフォーマットへのエンコード
  3. ファイル書き込み

1は、ScreenCapture.CaptureScreenshotIntoRenderTexture が2019.1で追加され、ようやく非同期でシステムメモリに読み戻せるようになりました。

1で読み戻したメモリはレンダーテクスチャに指定したフォーマットのバイト配列(NativeArray<byte>)ですが、これを一般的な画像ファイルフォーマットにエンコードするには 2017.1から追加されているImageConversionクラスのAPI、ImageConversion.EncodeToPNG など(フォーマット別)を使用します。しかし、これは引数にバイト配列ではなくTexture2D を要求する上に、メインスレッドのみ呼び出し可能なので同期処理を避けられません。
流石に使えないAPIだと思ったのか、2019.3 でバイト配列(byte[])を使用する ImageConversion.EncodeArrayToPNG が追加されました。リファレンスにも”This method is thread safe.”と書かれていて、メインスレッド以外からの呼び出しが許可されています。

3は、.Net APIで以前から非同期可能です。

これらを組み合わせれば、”ほぼ”非同期にスクリーンキャプチャを行えます。

 

今後改善して欲しいところ。

  • ScreenCapture.CaptureScreenshotIntoRenderTexture リファレンスのサンプルコードが間違っている。
    using (var imageBytes = request.GetData<byte>()) で使用されているが、ユーザがこのNativeArrayに対してusingや明示的なDisposeの呼び出しを行うと、例外が出力される(InvalidOperationException: The NativeArray can not be Disposed because it was not allocated with a valid allocator.)。AsyncGPUReadbackRequest が管理しているはず?
  • NativeArray<byte>からbyte[]の変換をメインスレッドで行う必要があるが、そこで巨大なマネージドメモリのアロケートが走る。
    NativeArray<byte>のまま処理するAPI、つまりJob System with Burstでエンコードを行って欲しい。
  • ImageConversion.EncodeArrayToPNG のエンコード済みバイト列として巨大なマネージドメモリのアロケートが走る。
    必要メモリ量の計算と、事前確保したメモリを使用するAPIが欲しい。NativeArrayでの非同期ファイル読み書きをサポートして欲しい。
  • 要するに、最初から最後までNativeArrayのまま処理が完結するようにして欲しい。
  • ImageConversion.EncodeArrayToPNG は出力フォーマットの指定ができない。つまり入力フォーマットと出力フォーマットは同一になる。また、RGBAのデータをRGBしかもたないJPGにすると、rowBytesを指定してもRGBAからRGBへ変換してくれないようだ。
  • 上下が反転している。グラフィクスAPI依存?ImageConversion.EncodeToPNG はTexture2D の段階でそれが打ち消されている?
    ユーザが面倒を見るべき処理ではないので、内部で処理して欲しい。

 

追記:
2019.4で ImageConversion.EncodeNativeArrayToPNG が追加されていました。やったね。

TwitchChatPlugin 1.0 for Yukarinette

TwitchChatPlugin 1.0 on GitHub

TwitchChatPlugin は、ゆかりねっとで音声認識した文章をTwitchの自身のチャンネルに発言することが出来ます。使用にはチャット用OAuthの取得が必要ですが、詳細はREADMEを読んで下さい。

streamingラグを考慮した遅延送信機能と、スパム抑制機能を追加しています。遅延時間は自身の配信設定やTwtichサーバーとのラグを考慮しながらいい感じに調整してみてください。

TwitchChatPlugin 0.1 for Yukarinette

ゆかりねっとプラグインを作りました。

TwitchChatPlugin 0.1 on GitHub

TwitchChatPlugin は、ゆかりねっとで音声認識した文章をTwitchの自身のチャンネルに発言することが出来ます。使用にはチャット用OAuthの取得が必要ですが、詳細はREADMEを読んで下さい。

ニコニコ動画やYoutube Liveでは既に同種のプラグインはあるのに、私が主に利用しているTwitch向けには無かったというので、やってみようかなと思ったら割と楽に出来たやつです。一番大変だったのはWPFでのウインドウ作りだったかもしれない。

とはいえそれよりも面倒臭そうな、streamingラグを考慮した遅延送信とスパムコントロールは後回しです。非同期処理が避けて通れませんが、使用しているTwtichLibに非同期メソッドが容易されていなさそうなのと、適当にスレッドプールに投げて終わりというわけには行かないだろうなという状況があるので。
そういうわけでバージョンは0.1のpre-releaseとなっています。

もう一つ、汚い言葉を使用したときのフィルタリングも機能も本来は必要で、これが無いとTwitch側の機械判断 (AutoMod) に引っかかってペナルティをもらう可能性があります。そういう言葉を使わない善良な人でも音声認識の都合、誤認識で思わぬワードが出ることもあるので注意して下さい。
これはGoogleの音声認識部分である程度はやってくれるのと、Twitch側の処理は日本語に対してはまだそう厳しくないだろう(未対応の可能性すらある)というのと、ゆかりねっとアプリケーション側でやったほうがいい機能だろうかつ、やってくれそうという判断から優先度は低いです。

SubtitlePlugin 1.0 for Yukarinette

作ったと言うほどのものではありませんが、ゆかりねっとプラグインを作りました。

SubtitlePlugin 1.0 on GitHub

SubtitlePluginは、ゆかりねっとの詳細字幕ウインドウを、読み上げ機能無しに使用するプラグインです。なんと5行書いただけの何もしない、いわゆるnullデバイス的なやつです。

ゆかりねっとでは、字幕表示をする場合、簡易字幕と詳細字幕がありますが、簡易字幕による字幕表示のウインドウはChromeのそれであり、キャプチャツールでこれを取り込むにはかえって手間がかかります。簡易字幕はウインドウ名が親ウインドウと被っているので、OBSの場合では音声認識を開始する度にキャプチャ先を設定し直さなくてはなりません。
そこで、通常のWindowsのウインドウである詳細字幕を用いたいところですが、私の見落としでなければ、この詳細字幕ウインドウを利用するには読み上げ機能のプラグインを必ず一つは選択する必要があり、しかもその機能から呼び出される読み上げアプリケーションなりが使用可能な状態でなければ、そのプラグインは無効化されます。つまり、読み上げ機能無しに字幕機能だけを使うことが出来ないのです。

読み上げ機能無しにゆかりねっとを用いるなんて意味無いじゃないかと思われるかも知れませんが、個人的には読み上げ機能は無くていいかなという感じでしたし、字幕のためにわざわざ適当な、特にフリーの読み上げアプリケーションを有効にして、気の抜けるような読み上げ音声を聞かなくてはならないというのはナンセンスなのです。
また、googleの音声認識APIを呼び出して字幕として出力するアプリケーションをフルスクラッチで作るよりも、既に組み込まれているゆかりねっとのプラグインとして作った方が楽だろうという判断です。結果的に開発者に要望を出す手間よりも楽でした。