Skip to content

Releases: routersys/YMM4-LuaScript

v1.14.0

Choose a tag to compare

@github-actions github-actions released this 03 Jul 14:22

v1.14.0 - Lua スクリプト for YMM4

標準の Lua には無い簡易な記法をまとめて追加したリリースです。比較の is、否定の is not、論理演算子の別名、複合代入、nil 合体、範囲指定の for など、キーボードで打ちやすく入力量を減らすための糖衣構文を導入しました。これらの記法はスクリプトの実行前に等価な標準 Lua へ変換され、MoonSharp、ネイティブ、カーネルのいずれの実行経路でも同じ結果になります。変換の基盤は属性から生成するトークン規則として設計しており、記法を 1 つ増やす場合はクラスを 1 つ追加するだけで反映されます。あわせて、エラー表示が書き換え後の行を正しく扱うように改め、新しい記号を使うとパラメータの表示判定が無効になる不具合を修正しました。既存のスクリプトの書き方と実行結果に変更はありません。


新機能

構文拡張

標準の Lua には無い簡易な記法をいくつか追加しました。いずれも実行前に等価な標準 Lua へ変換されるため、実行結果は手書きの標準 Lua と同じになります。変換の入口は Lua に存在しない記号または語順に限っており、文字列とコメントの内側は変換しません。

  • 比較では、a is b が a == b、a is not b が a ~= b、a != b が a ~= b へ変換されます。is と is not は前後が値になる位置でのみ働くため、is という名前の変数とは衝突しません。
  • 論理では、!a が not a、a && b が a and b、a || b が a or b へ変換されます。
  • 複合代入では、+= -= *= /= %= ^= ..= を使えます。x += 1 は x = x + (1) へ展開し、右辺を括弧で囲むため優先順位は保たれます。
  • nil 合体では、a ?? b は a が nil のときだけ b を返します。a は一度だけ評価し、false や 0 は a の値としてそのまま返します。x ??= b は x が nil のときだけ b を代入します。
  • 論理代入では、x ||= b が x = x or (b)、x &&= b が x = x and (b) へ変換されます。
  • インクリメントでは、x++ が x = x + 1 へ変換されます。
  • 範囲指定の for では、for i in <0..10> が for i = 0, 10 と同じく終端を含む反復になります。for i in <0..<10> は終端を含まず、for i in <0..10, 2> は増分を 2 に指定します。

各記法の説明と例は、プラグイン付属のドキュメントおよびサイトの構文拡張のページへ追記しています。


互換性・後方互換

  • 追加した記法はすべて、標準の Lua には無い記号または語順を入口にしています。既存のスクリプトはそのまま動作し、実行結果も変わりません。
  • 変換は文字列とコメントの内側には及びません。行数は保たれ、整形とコメントもそのまま残ります。
  • 変換はすべての実行経路へ適用されます。MoonSharp、ネイティブ、カーネルのいずれで実行しても同じ結果になります。
  • v1.13.4 までの仕様に変更はありません。

内部実装

  • 書き換えの基盤として、空白とコメントと文字列を保持する可逆のトークン字句解析器を新設しました。カーネル抽出が使う不可逆の字句解析器とは要件が異なるため、別の実装として分けています。
  • 各記法は LuaSyntaxRule 属性を付けた 1 つのクラスとして実装し、ILuaSyntaxRule インターフェースの判定処理だけを持ちます。ソースジェネレータがこれらのクラスを収集し、優先順位で並べた規則レジストリを生成します。記法の追加はクラスの追加だけで完結し、中央の分岐を書き換える必要はありません。
  • 規則レジストリの生成器は、Lua API を生成する既存のジェネレータとは責務が異なるため、独立したジェネレータとして分離しました。
  • nil 合体の a ?? b は、a を一度だけ評価するために無名関数の即時呼び出しへ展開します。nil 合体代入の x ??= b は条件文へ展開します。複合代入と論理代入は、左辺と演算子から等価な代入文を組み立てます。
  • エラー表示では、書き換えが変更した行を記録し、その行の診断は桁ではなく行全体を対象にします。これにより、変換した独自構文の上へ誤って波線が乗ることを防ぎます。変更していない行では、報告された桁の情報をそのまま使います。この記録はソースの変更時に一度だけ作り、毎フレームの処理では文字列比較もメモリ確保も増やしません。
  • パラメータの表示判定を、カーネルの字句解析器から新しい可逆の字句解析器へ移しました。従来は新しい記号でカーネルの字句解析器が例外を投げ、スライダーとチェックと色の表示判定が無効になっていました。
  • テストは 3215 件です。v1.13.4 の 3113 件から、各記法の変換結果と評価結果の検証、変換後の独自構文がネイティブでも動作することの検証、変更行の記録の検証、および新しい記法を使ってもパラメータの表示判定が働くことの検証を追加しました。

v1.13.4

Choose a tag to compare

@github-actions github-actions released this 03 Jul 10:28

v1.13.4 - Lua スクリプト for YMM4

環境情報を取得する obj.getinfo を追加したリリースです。
スクリプトの設置フォルダのパスや動画の出力状態に加えて、最大画像サイズ、BPMグリッドの情報、経過時間、本体のバージョンを名前で取得できます。MoonSharp とネイティブの両エンジンで同一の関数として動作します。
あわせて、プラグインの内部構成を依存関係の層ごとの複数アセンブリへ分割し、Lua API の登録と入力補完をソースジェネレータによる宣言的な生成へ移行しました。既存のスクリプトの書き方と実行結果に変更はありません。


新機能

obj.getinfo による環境情報の取得

obj.getinfo(名前) は、名前で指定した環境情報を返します。対応していない名前を指定した場合は nil を返します。取得できる情報は次のとおりです。

  • "script_path" は、プラグインの設置フォルダのパスを返します。末尾には区切り文字が付きます。
  • "filter" は、フィルタ効果として処理中かどうかを返します。本プラグインでは常に true を返します。
  • "saving" は、動画を出力中のときだけ true を返します。
  • "image_max" は、最大画像サイズを横幅と高さの2つの値で返します。
  • "bpm" は、BPMグリッドのテンポと拍子と基準時間の3つの値を返します。基準時間の単位は秒です。BPMグリッドを設定していない場合はテンポが 0 になります。
  • "clock" は、YMM4 の起動からの経過時間を秒で返します。
  • "script_time" は、スクリプトの実行開始からの経過時間をミリ秒で返します。
  • "version" は、本体のバージョンを major×10000+minor×100+build の数値で返します。

編集中のみプレビューへ枠を描き、出力時には描かないといった分岐へ利用できます。


互換性・後方互換

  • 既存のスクリプトの書き方と実行結果に変更はありません。obj.getinfo は新規の関数であり、従来の呼び出しへは影響しません。
  • obj.getinfo は MoonSharp とネイティブの両エンジンで動作します。script_path、filter、saving、image_max、bpm、version は両エンジンで同一の値を返します。clock と script_time は経過時間の計測であり、値そのものは実行のたびに変わります。
  • v1.13.3 までの仕様に変更はありません。

内部実装

  • プラグインを依存関係の層ごとに LuaScript.Kernel、LuaScript.Compat、LuaScript.Media、LuaScript.Runtime、および本体の 5 つのアセンブリへ分割しました。名前空間は据え置き、参照の向きを一方向へ整理しています。
  • Lua API の登録と毎フレームの変数投影を、属性から生成するソースジェネレータへ移行しました。入力補完の候補もこの宣言から生成し、手書きの一覧を廃止しました。関数を 1 つ追加すると、登録と補完へ自動的に反映されます。
  • Kernel、Compat、Runtime の各プロジェクトを 1 ファイル 1 クラスへ整理し、ドメインごとのフォルダへ再配置しました。エンジンのテーブル管理は LuaScope へ汎用化しています。
  • 映像デコーダを LuaScript.Media プロジェクトへ分離し、ツールバーを View と ViewModel へ分離しました。ViewModel はフレームワークに依存しない構成へ整理しています。
  • obj.getinfo の実装では、BPMグリッドの情報を YMM4 のシーンから取得し、script_path と version は本体からエンジンへ渡します。経過時間は両エンジンがそれぞれ高精度タイマーで計測します。
  • テストは 3113 件です。v1.13.3 の 3092 件から、obj.getinfo の両エンジンでの実行結果の検証と、補完カタログの回帰検証、およびエンジンのテーブルライフサイクルの特性化検証を追加しました。

v1.13.3

Choose a tag to compare

@github-actions github-actions released this 03 Jul 00:01

v1.13.3 - Lua スクリプト for YMM4

obj.setfont の引数の解釈を MoonSharp とネイティブの両エンジンで統一したリリースです。
これまで両エンジンは通常の呼び出しでは同じ結果を返していましたが、引数へ想定外の型や値を渡した場合の挙動が食い違っており、ネイティブエンジンにはスクリプト全体をエラーにする経路が存在しました。今回から、どのような引数を渡しても両エンジンが同一の結果を返します。
あわせて、スクリプトエディタの入力補完へ、ドキュメントに記載済みで未登録だった obj テーブルの関数 12 件を追加しました。
呼び出しの書き方と関数の引数に変更はありません。通常の使い方への影響はありません。


動作の変更

1. obj.setfont の引数の解釈を両エンジンで統一

obj.setfont(フォント名, サイズ, スタイル, 色) の各引数について、想定外の型や値を渡した場合の挙動を次のとおり統一しました。

  • フォント名へ数値を渡した場合、両エンジンとも文字列へ変換して採用します。これまで MoonSharp は無視し、ネイティブは真偽値やテーブルまで文字列化していました。文字列と数値以外の値は両エンジンとも無視し、直前の設定を保持します。
  • サイズへ数値文字列を渡した場合、両エンジンとも数値へ変換して採用します。これまでネイティブは文字列のまま保持し、後続の obj.load("text") の呼び出しでスクリプト全体が実行時エラーになっていました。数値へ変換できない値は両エンジンとも無視し、直前の設定を保持します。
  • スタイルへ数値へ変換できない値を渡した場合、両エンジンとも無視して直前の設定を保持します。これまで MoonSharp は 0 として太字と斜体を解除し、ネイティブは実行時エラーになっていました。
  • スタイルの小数と負数は、両エンジンとも床関数で整数化してからビットを判定します。これまで MoonSharp はゼロ方向への切り捨てを行っており、負の小数で結果が食い違っていました。
  • スタイルへ NaN・無限大・2^53 を超える数値を渡した場合も、両エンジンとも同一の結果(太字と斜体の解除)になります。これまで MoonSharp は変換の飽和により値ごとに異なるフラグが立つことがありました。
  • 色へ数値へ変換できない値を渡した場合、両エンジンとも無視して直前の設定を保持します。

2. スクリプトエディタの入力補完へ obj テーブルの関数 12 件を追加

ドキュメントに記載済みで入力補完に未登録だった次の関数を、候補へ追加しました。
obj.getobject、obj.putpixeldata、obj.setfont、obj.draw、obj.drawpoly、obj.copybuffer、obj.getvalue、obj.setoption、obj.getoption、obj.pixeloption、obj.setanchor、obj.effect の 12 件です。
並び順はドキュメントの「obj テーブル - 関数」の記載順に合わせています。


互換性・後方互換

  • 呼び出しの書き方と関数の引数に変更はありません。フォント名に文字列、サイズ・スタイル・色に数値を渡す通常の使い方の結果は変わりません。
  • 引数を省略した場合と nil を渡した場合は、両エンジンとも直前の設定を保持します。
  • フォントの既定値(フォント名なし・サイズ 34・標準スタイル・色 0xFFFFFF)と、実行ごとに既定値へ戻る仕様は変わりません。
  • scene.set / scene.get を含む v1.13.2 の仕様に変更はありません。

内部実装

  • MoonSharp 側の setfont の引数解釈とフォント状態を AviUtlFontState として独立した型へ抽出しました。LuaScriptEngine はフォントの 5 つのフィールドを持たず、この型へ委譲します。テストレーンはソースリンク方式で LuaScriptEngine を参照できないため、SceneTableRegistrar と同じ「純粋な単位を切り出してリンクする」構成に従ったものです。
  • スタイルのビット判定は Lua の剰余と同じ床剰余(値 - floor(値 / 除数) * 除数)で行います。C# の変換の飽和(NaN が 0、範囲外が最大値へ丸められる仕様)を経由しないため、非有限値と巨大な値でも LuaJIT の math.floor と剰余の結果に一致します。
  • worker.lua の setfont へ型検査と tonumber による変換を導入しました。フォント名は文字列と数値のみ受理し、サイズ・スタイル・色は数値へ変換できた場合のみ採用します。変換できない値が共有メモリの数値領域へ渡って ffi の変換エラーになる経路を排除しました。
  • 入力補完は LuaAutoCompletionStrategy の obj 名前空間の候補配列への追加のみで、補完の仕組みに変更はありません。
  • テストは 3092 件です。v1.13.2 の 3086 件から、AviUtlFontState の既定値とリセット、引数の変換規則、負数スタイルの床セマンティクス、非有限値の扱いの検証と、ネイティブワーカーで同一の呼び出し列を実行して同じ期待値と照合する等価性の検証を追加しました。

v1.13.2

Choose a tag to compare

@github-actions github-actions released this 02 Jul 23:32

v1.13.2 - Lua スクリプト for YMM4

scene.set / scene.get の値の見え方を、フレーム位置に対して決定論的なモデルへ変更したリリースです。
共有領域を「どのフレームで何を書き込んだか」を記録する履歴として再設計し、各フレームの読み取りは「そのフレームより前に確定した最新の値」を返すようにしました。これにより、タイムラインをどの順番でシークしても、同じフレームでは同じ値を読み取ります。あわせて、書き込みの確定に次のフレームの評価を必要としないようにし、同じフレームで複数のアイテムが同じ名前へ書き込んだ場合の優先規則を定め、動画出力とアイテムエフェクトの編集画面を編集中のプレビューから分離し、履歴が使うメモリへ上限を設けました。
呼び出しの書き方と関数の引数に変更はありません。scene.set / scene.get を使わないスクリプトへの影響はありません。


動作の変更

1. 値の見え方をフレーム位置に対して決定論的なモデルへ変更

v1.13.1 までは、各アイテムの書き込みを保留領域へため、次のフレームの評価が行われた時点で共有領域の現在値へ反映していました。このため、読み取れる値が「どのフレームを評価してきたか」というシークの経路に左右され、前のフレームへ戻ったときに後のフレームで書き込まれた値が見えることがありました。
今回から、書き込みをフレーム番号付きの履歴として記録し、scene.get は「自分のフレームより前に確定した最新の値」を返すようにしました。
自分のスクリプトが書き込んだ値は、同じ実行の中で直後の scene.get からそのまま読み取れます。他のアイテムが書き込んだ値は、次のフレーム以降の評価から読み取れます。
同じフレームの中では、アイテムがどの順番で評価されても scene.get が返す値は変わりません。

2. ランダムシークへの対応

タイムライン上をどの順番でシークしても、各フレームの読み取り結果は変わりません。
前へ戻ったフレームでは、そのフレームより後に書き込まれた値は見えず、そのフレームより前に書き込まれた値だけが見えます。
書き込んだフレームの直後のフレームを評価しなくても、それより後のどのフレームからでも読み取れます。
同じフレームを何度再評価しても、読み取れる値と書き込みの結果は同一です。

3. 同じフレームで複数のアイテムが同じ名前へ書き込んだ場合の規則

同じフレームで複数のアイテムが同じ名前へ書き込んだ場合、レイヤー番号の大きいアイテムの書き込みが優先されます。
アイテムは並列に評価されますが、この規則により結果は評価のタイミングに依存しません。
同じアイテムの中で複数の Lua スクリプトエフェクトが同じ名前へ書き込んだ場合は、エフェクトチェーンの後段の書き込みが優先されます。

4. 動画出力とアイテムエフェクトの編集画面を編集中のプレビューから分離

動画出力は編集中のプレビューとは独立した空の共有領域から始まります。編集画面での試行の途中経過が出力へ持ち込まれることがなくなり、同じプロジェクトを出力すれば毎回同じ結果になります。出力が終わると、その出力で使った共有領域は破棄されます。
アイテムエフェクトの編集画面のプレビューも独立した共有領域を使うため、編集画面を開いても編集中のプレビューの共有値は変化しません。
現在のフレームの画像出力は編集中のプレビューと同じ共有領域を参照するため、保存される画像はプレビューの表示と一致します。v1.13.1 までは画像出力が共有領域を全消去していましたが、この副作用はなくなりました。

5. 履歴のメモリへ上限を追加

各名前の最新の値を除いた履歴が使うメモリは 16MB までとし、超過した場合は全体で最も古い記録から順に間引きます。最新の値は間引きの対象になりません。
1 つのシーンに保存できる名前が 4096 個までである仕様は、v1.13.1 から変わりません。


互換性・後方互換

  • 呼び出しの書き方と関数の引数に変更はありません。scene.set / scene.get を使わないスクリプトへの影響はありません。
  • スクリプトがエラーまたはタイムアウトで終了したフレームの書き込みを反映しない仕様は、v1.13.1 から変わりません。
  • 名前と文字列値を UTF-8 換算で 4095 バイトへ切り詰める仕様は、v1.13.0 から変わりません。
  • nil を渡した削除は、削除の記録として履歴へ残ります。削除より前のフレームでは削除前の値を、削除より後のフレームでは nil を読み取ります。
  • 共有値はメモリ上にのみ保持し、プロジェクトファイルには保存しません。YMM4 を終了すると失われます。

内部実装

  • SceneSharedValues を世代スナップショット方式からフレーム索引付きの履歴方式へ再設計しました。名前ごとに「フレーム番号・レイヤー番号・値」の組をフレーム昇順で保持し、読み取りは自分のフレームより前の最新の組を二分探索で求めます。nil の書き込みは削除の記録として履歴へ残し、直前の値と同じ書き込みは記録しません。保留領域と世代の追跡、出力開始の検出によるリセットは撤廃しました。
  • 共有領域を描画パイプラインごとに分離しました。YMM4 は動画出力・画像出力・アイテムエフェクトの編集画面のそれぞれで専用のグラフィックデバイスを生成するため、デバイスのインスタンスを鍵とした ConditionalWeakTable で領域を引き当てることで、出力は毎回空の領域から始まり、出力の終了後は領域が GC で解放されます。編集中のプレビューはアプリケーションの実行中を通して同じデバイスを使うため、領域が維持されます。
  • 同じフレームの同じ名前への書き込みが競合した場合、レイヤー番号の大きい書き込みを採用し、同じレイヤーでは後から確定した書き込みで置き換えます。並列評価でも結果が発行順序に依存しません。
  • SceneValueSession の開始時にスコープとレイヤー番号を受け取るようにし、正常終了時の発行でフレーム番号とレイヤー番号を付けて履歴へ即時確定します。書き込みバッファと読み取りメモ化、参照の記録は従来どおりです。
  • LuaScriptEffectProcessor のフレームキャッシュの検証を履歴照合へ変更しました。記録した読み取り結果を現在のフレームの履歴と照合し、食い違うフレームでは再実行します。書き込みは履歴として保持され再発行が不要になったため、共有値を書き込んだフレームのキャッシュ再利用の禁止を撤廃しました。
  • 各名前の最新の組を除いた履歴のメモリ使用量を追跡し、16MB を超えた場合は全体で最も古い組から決定論的に間引きます。
  • NativeProtocol と worker.lua に変更はありません。ワーカーの実行内キャッシュのセマンティクスは新しいモデルとそのまま一致します。
  • テストは 3086 件です。v1.13.1 の 3080 件から、履歴の可視性とランダムシークの決定論、後戻りシークでの挿入、レイヤーによる競合解決、nil の削除記録、再発行の冪等性、履歴メモリの上限、スコープの分離の検証を追加しました。

v1.13.1

Choose a tag to compare

@github-actions github-actions released this 02 Jul 23:06

v1.13.1 - Lua スクリプト for YMM4

v1.13.0 で追加した scene.set / scene.get の値の見え方を、アイテムの評価順序に依存しない確定的なモデルへ変更したリリースです。
同じフレームの中ではどのアイテムから評価しても scene.get が返す値が変わらないようにし、他のアイテムが書き込んだ値は次のフレームの評価から読み取れるようにしました。あわせて、スクリプトがエラーやタイムアウトで終了したフレームの書き込みを共有領域へ反映しないようにし、動画出力の開始時に共有領域をリセットし、1 つのシーンに保存できる名前の数へ上限を設けました。
呼び出しの書き方と関数の引数に変更はありません。scene.set / scene.get を使わないスクリプトへの影響はありません。


動作の変更

1. scene.set / scene.get の値の見え方を確定的なモデルへ変更

これまで scene.set は共有領域へ即座に書き込んでいたため、同じフレーム内で別のアイテムが書き込んだ値を読み取れるかどうかが、アイテムの評価順序に左右されていました。
今回から、各アイテムの書き込みはそのアイテムの実行が正常に終わった時点でまとめて共有領域へ反映し、他のアイテムからは次のフレームの評価で読み取れるようにしました。
自分のスクリプトが書き込んだ値は、同じ実行の中で直後の scene.get からそのまま読み取れます。
同じフレームの中では、アイテムがどの順番で評価されても scene.get が返す値は変わりません。フレーム単位のスナップショットを読み取るため、評価順序に依存しない結果になります。

2. スクリプトがエラーまたはタイムアウトで終了したフレームは書き込みを反映しない

スクリプトがコンパイルエラー、実行時エラー、またはタイムアウトで終了したフレームでは、その実行の中で行った scene.set の書き込みを共有領域へ反映しないようにしました。
正常に最後まで実行できたフレームの書き込みのみが、次のフレームの評価へ引き継がれます。

3. 動画出力の開始時に共有領域をリセット

動画出力を開始すると、シーンの共有領域を空の状態から始めるようにしました。
編集画面での試行の途中経過が出力へ持ち込まれることがなくなり、同じプロジェクトを出力すれば毎回同じ結果になります。

4. 1 つのシーンに保存できる名前の数へ上限を追加

1 つのシーンに保存できる名前を 4096 個までとしました。
上限に達した後に新しい名前へ書き込もうとした場合、その書き込みは無視します。すでに保存されている名前への上書きと、nil を渡した削除は、上限に関わらず行えます。


互換性・後方互換

  • 呼び出しの書き方と関数の引数に変更はありません。scene.set / scene.get を使わないスクリプトへの影響はありません。
  • 同じフレーム内で他のアイテムの書き込みを読み取っていたスクリプトは、読み取れる値が 1 フレーム前の値へ変わります。フレームをまたいで値を受け渡す使い方には影響しません。
  • 名前と文字列値を UTF-8 換算で 4095 バイトへ切り詰める仕様は、v1.13.0 から変わりません。
  • 共有値はメモリ上にのみ保持し、プロジェクトファイルには保存しません。YMM4 を終了すると失われます。

内部実装

  • SceneSharedValues をシーンごとの世代スナップショット方式へ再設計しました。確定済みの値を保持する辞書と、次の世代へ反映する保留中の書き込みを保持する辞書を分け、タイムラインのフレーム番号を世代として、世代が変わったときに保留中の書き込みを確定済みへ反映します。出力中は、出力へ入った直後と世代が前へ戻ったときに、両方の辞書を空にします。名前の正規化と値の正規化を静的メソッドとして切り出しました。
  • SceneValueSession を追加しました。1 つのアイテムの実行の間、書き込みをバッファへため、読み取った結果をメモ化し、参照した名前と結果を記録します。実行の開始でシーン識別子と世代と出力中かどうかを受け取り、正常終了時に書き込みをまとめて共有領域へ発行します。書き込みを優先して返すため、同じ実行の中では直後の scene.get が書き込んだ値を返します。
  • AviUtlScriptContext のシーン共有値のアクセスを SceneValueSession への委譲へ変更しました。LuaScriptEffectProcessor は実行の準備で BeginSceneValues を呼んでセッションを開始し、スクリプトが正常に終わった後に PublishSceneValues を呼んで書き込みを発行します。スクリプトが例外で終了したフレームでは PublishSceneValues へ到達しないため、書き込みは発行されません。
  • LuaScriptEffectProcessor のフレームキャッシュの検証を世代対応へ変更しました。キャッシュの再利用可否を判定する際、記録した読み取り結果を現在のフレームと出力状態に対応するスナップショットと照合します。
  • NativeProtocol と worker.lua のコールバックタグ領域を 4096 バイトから 8192 バイトへ拡張しました。文字列を保存する scene.set は名前と値を区切り文字を挟んで 1 つのタグ領域へ格納するため、名前と値をそれぞれ 4095 バイトまで、互いを切り詰めずに転送できるようにしました。
  • worker.lua の scene.get / scene.set へ実行内キャッシュを追加しました。同じ実行の中で同じ名前を繰り返し読み取る場合や、書き込んだ直後に読み取る場合に、共有メモリ経由の往復を行わずに手元の値を返します。キャッシュは各実行の開始で消去します。
  • worker.lua の名前と文字列値の切り詰めを UTF-8 の文字境界で行うようにし、管理側の 4095 バイトの切り詰めと結果を一致させました。
  • テストは 3080 件です。v1.13.0 の 3063 件から、ストアの世代と出力時リセットと容量上限の検証、SceneValueSession の可視性とトランザクション性の検証、scene テーブルのセッション経由の検証、ネイティブワーカーでの IPC 回数と最大長の往復の検証を追加しました。

v1.13.0

Choose a tag to compare

@github-actions github-actions released this 02 Jul 14:35

v1.13.0 - Lua スクリプト for YMM4

シーン単位で値を共有する scene.set / scene.get と、AviUtl 互換のグローバル関数を追加したリリースです。
アイテムやフレームをまたいだ値の受け渡しと、RGB / HSV による色計算、ビット演算、デバッグ出力を、MoonSharp とネイティブの両エンジンで同一に扱えるようにしました。
いずれも既存のスクリプトと API に影響しない追加で、従来の呼び出しはそのまま動作します。


新機能

1. シーン単位で値を共有する scene.set / scene.get を追加

scene.set(name, value) はシーン単位の共有領域へ値を保存し、同じシーン内のすべての Lua スクリプトエフェクトから scene.get(name) で参照できます。
アイテムやフレームをまたいで値を受け渡せるため、グローバル変数がフレーム間で保持されない制約を、共有領域を介して回避できます。
保存できる値は数値・文字列・真偽値で、nil を渡すと削除します。テーブルや関数などそれ以外の値は保存しません。
scene.get は未設定の名前に対して nil を返します。
名前と文字列値は UTF-8 換算で 4095 バイトを超える部分を切り捨てます。
共有値はシーンごとに独立しており、シーン識別子を鍵として YMM4 を終了するまでメモリ上に保持します。プロジェクトファイルには保存しません。
アイテム間の評価順序は保証しないため、同一フレーム内での書き込みと読み取りの順序に依存する作りは避けてください。
MoonSharp とネイティブのどちらのエンジンでも同一に動作します。

2. AviUtl 互換のグローバル関数を追加

グローバルスコープから RGB / HSV / OR / AND / XOR / SHIFT / debug_print を直接呼び出せるようにしました。
RGB(r, g, b) は RGB 各要素を 0xRRGGBB の色情報へ合成し、RGB(col) は色情報を r, g, b の 3 値へ分解します。RGB(r1, g1, b1, r2, g2, b2) は obj.time / obj.totaltime の進行に合わせて一色目から二色目へ直線的に変化する色情報を返します。
HSV も同様に色相・彩度・明度と色情報を相互に変換し、6 引数指定で時間変化します。色相は 0 から 360、彩度と明度は 0 から 100 の範囲で扱います。
OR / AND / XOR は 32bit 整数のビット演算で、小数は 0.5 ちょうどまでを切り捨てて整数化します(2.50 は 2、2.51 は 3)。
SHIFT(a, shift) は算術シフトで、shift が正で左シフト、負で右シフトします。
debug_print(text) は文字列を OutputDebugString() へ送信し、DebugView などで確認できます。スクリプトの実行エラーも自動で送信します。
これらの関数は MoonSharp とネイティブのどちらのエンジンでも同一の結果を返します。

3. エディタの入力補完へ追加

上記のグローバル関数と scene.set / scene.get を、スクリプトエディタの入力補完の候補へ追加しました。


互換性・後方互換

  • 既存のスクリプトの書き方と API に変更はありません。追加した関数と scene.set / scene.get はいずれも新規で、従来の呼び出しに影響しません。
  • これまで未対応だった scene.set / scene.get に対応しました。AviUtl の同名関数を使うスクリプトが、シーン内での値共有として動作します。
  • RGB / HSV / OR / AND / XOR / SHIFT / debug_print はグローバル名として追加されます。スクリプト側で同名のグローバルを定義した場合は、スクリプト側の定義が優先されます。
  • 共有値はメモリ上にのみ保持し、プロジェクトファイルには保存しません。YMM4 を終了すると失われます。

内部実装

  • SceneSharedValues がシーン識別子ごとに共有辞書を保持し、名前と文字列値を UTF-8 で 4095 バイトへ切り詰めます。
  • AviUtlScriptContext がシーン共有値の取得と書き込みを仲介し、読み取った名前と結果、書き込みの有無を記録します。
  • LuaScriptEffectProcessor は記録した読み取り結果と書き込みの有無をフレームキャッシュへ持ち込み、共有値を書き込んだフレーム、または読み取った値が現在値と食い違うフレームではキャッシュを使わず再実行します。
  • MoonSharp では AviUtlGlobalRegistrar がグローバル関数を、SceneTableRegistrar が scene.set / scene.get を登録します。時間変化の割合は obj.time / obj.totaltime から求めます。
  • ネイティブでは NativeProtocol へ scene 取得と設定のコールバック種別を追加し、LuaJitWorker が名前と値を共有メモリ経由でやり取りします。文字列は名前と値を区切って 1 つのタグ領域へ格納します。
  • worker.lua が scene.get / scene.set のブリッジと時間変化の割合の設定を行い、shim.lua が RGB / HSV / OR / AND / XOR / SHIFT / debug_print を実装します。
  • スクリプトのタイムアウトと実行時例外のメッセージも、debug_print と同じ OutputDebugString の経路へ送信します。
  • テストは 3063 件です。v1.12.0 の 3041 件から、シーン共有値の保存と削除と切り詰め、scene テーブルへの登録、グローバル関数のエンジン間の一致、ネイティブワーカーでの往復などの検証を追加しました。

v1.12.0

Choose a tag to compare

@github-actions github-actions released this 02 Jul 10:56

v1.12.0 - Lua スクリプト for YMM4

ネイティブレーンとカーネルの性能をまとめて引き上げたリリースです。プロセス間の
画素転送、draw 呼び出しの往復、スクリプト本文の転送と比較、getpixeldata の実装、
CPU カーネルの命令並列という経路ごとの無駄を系統的に削りました。あわせて、
カーネル抽出の検査漏れや math.fmod の剰余の種類など、結果の正しさに関わる不具合を
修正しました。全体の設計は「識別子と版数による変更検知」と「消費される境界での
遅延実体化」で統一しています。


改善

1. ネイティブレーンの画素転送を直結化

ネイティブレーンでは、Direct2D のステージングビットマップと共有メモリの間に中間の
バッファを挟んでいたため、入力の転送で 2 回、結果の読み戻しで 2 回の複製が毎フレーム
発生していました。本リリースでは両者をポインタで直結し、入力はステージングの Map から
共有メモリへ、結果は共有メモリから出力ビットマップの CopyFromMemory へ、それぞれ
1 回の複製で転送します。

1920×1080 の BGRA フレームは約 8.3MB で、複製量は毎フレーム約 33MB から約 17MB へ
半減します。開発機の実測ではこの規模の複製 1 回が約 0.4ms なので、画素を書き換える
スクリプトで 1 フレームあたり約 0.8ms、4K では単純比例で約 3.2ms を複製から削れる
計算です。draw 合成やバッファ置換のように従来形式のバッファが必要な経路に限り、
そこでだけ実体化します。

2. draw と drawpoly の呼び出しをリングバッファで一括化

ネイティブレーンの obj.draw と obj.drawpoly は、1 回の呼び出しごとにプロセス間の
イベント往復を行っていました。本リリースでは共有メモリ上のリングバッファへ書き溜め、
容量の 4096 件に達したときと実行の終わりにまとめて回収します。1 フレームに 1000 回
draw するスクリプトなら、往復は 1000 回から 1 回になります。

3. getpixeldata を平坦な配列の遅延反映へ変更

ネイティブレーンの getpixeldata は、添字 1 回の読み書きごとに座標の分解と除算、
乗算済み表現との変換を行っていました。本リリースでは取得時に全画素を一度だけ
変換して平坦な配列を作り、以後の読み書きは配列参照 1 回になります。書き込みは
putpixeldata または次の画素操作の時点でまとめてフレームへ反映します。1920×1080 の
全画素を添字で走査すると約 830 万回のアクセスになるため、1 回あたりの費用の削減が
そのまま効きます。

4. getpixeldata の添字ループをカーネルとして実行

getpixeldata で得た画素を添字のループで書き換える定型を、getpixel と setpixel の
定型と同じようにカーネルとして抽出し、CPU カーネルで実行するようにしました。従来
この形はネイティブレーンで実行され、ワーカーへの画素転送を伴っていました。抽出後は
転送そのものが不要になります。出力は MoonSharp とバイト単位で一致します。

5. CPU カーネルに SIMD の実行経路を追加し、採用を実測で自動判定

CPU カーネルに Vector256 で 4 画素を同時に評価するブロック経路を追加しました。
倍精度で完全一致を保てる加減乗除、床剰余、符号反転、abs、floor、ceil、sqrt、比較と
選択だけを対象とし、min や max、pow、三角関数を含むカーネルは従来のスカラ経路で
実行します。出力はスカラ経路とバイト単位で一致します。

SIMD が有利かどうかはカーネルの内容と実行環境に依存し、並列実行でメモリ帯域が
飽和する環境では不利になる場合すらあります。そこで GPU カーネルのセルフ検証と同じ
流儀で、採用を実測で自動判定します。最初の数フレームで両経路を交互に実行して時間を
計測し、各経路の初回は JIT の暖機として計測から除いたうえで、速かった経路を
プログラム単位で恒久採用します。両経路の出力はバイト単位で一致するため、判定中の
切り替えが結果に現れることはありません。

開発機の 1920×1080 での実測では、単一スレッドの評価はグレースケール相当のカーネルで
約 1.6 倍から 2 倍、比較選択を多く含む重いカーネルで約 1.2 倍から 1.5 倍になりました。
フレーム全体の処理は行単位の並列実行でメモリ帯域が支配的になるため差は縮まり、
判定前の強制 SIMD では重いカーネルが約 2 割遅くなる場合がありましたが、自動判定に
よって常に速い側の経路で実行されます。

6. スクリプト本文の転送と比較を変更検知へ変更

ネイティブレーンはスクリプト本文を毎フレーム UTF-8 へ変換して共有メモリへ書き込んで
いました。本文は最大 128KB あるため、変換と複製と配列の割り当てが毎フレーム発生して
いました。本リリースでは本文へ版数を振り、変更したフレームだけ転送します。ワーカー側の
コンパイル結果も版数で保持し、同じ本文の再コンパイルを行いません。

フレームキャッシュの鍵も同様に、スクリプト本文の文字列比較から参照の版数比較へ
変更しました。長いスクリプトほど毎フレームの比較費用が大きかったため、これも定数時間に
なります。

7. copybuffer の複製でバッファを再利用

MoonSharp レーンの obj.copybuffer は、コピーのたびに新しい配列を割り当てていました。
寸法が同じ間は既存の配列へ上書きするように変更し、毎フレーム呼び出すスクリプトの
GC 圧力を取り除きました。


不具合修正

getpixeldata の未反映の書き込みをフレーム置換時に破棄

obj.load や obj.copybuffer でフレームが置き換わった直後に、置換前の getpixeldata へ
書き込んだ未反映の内容が新しいフレームへ流し込まれることがありました。フレームの
置換時に未反映の書き込みを破棄するように修正しました。

getpixeldata の色の復元順序を getpixel と統一

MoonSharp レーンの getpixeldata が乗算済み表現から色を復元する際の計算順序が
getpixel と食い違っており、丸めで 1 階調ずれる可能性がありました。getpixel の順序へ
統一し、MoonSharp、ネイティブ、カーネルの三経路が同じ結果を返すようにしました。

カーネル抽出の検査漏れを修正

ループ変数や getpixeldata の参照名を内側のローカル変数が同じ名前で覆い隠す
スクリプトを誤って抽出し、結果が変わる可能性がありました。該当する形の抽出を拒否し、
従来の経路で実行するように修正しました。あわせて、getpixeldata への書き込み値が
0 から 255 へ収められずにカーネル化されていた点を、MoonSharp と同じ挙動へ修正
しました。

math.fmod の剰余の種類を修正

カーネル実行の math.fmod が床方式の剰余で計算されており、負の値を渡したときに
Lua の math.fmod と符号の異なる結果を返していました。被除数の符号を保つ切り捨て
方式へ修正し、MoonSharp およびネイティブレーンと一致させました。

draw リングの読み出し件数を容量へ制限

ホストが共有メモリ上の draw の件数をそのまま信頼していたため、値が壊れた場合に
リングの範囲外を読み出す可能性がありました。件数を容量で制限するように修正しました。


互換性・後方互換

  • スクリプトの書き方と API に変更はありません。
  • カーネル実行で math.fmod を負の値に使っている場合は結果が変わります。従来の結果が
    誤りで、修正後は MoonSharp と同じ結果になります。
  • SIMD 経路の出力はスカラ経路とバイト単位で一致します。対象外の演算を含むカーネルは
    従来のスカラ経路で実行するため、出力の正しさに妥協はありません。採用の自動判定は
    実行時間だけを比較するもので、どちらの経路が選ばれても結果は同一です。
  • getpixeldata の書き込みがフレームへ反映されるのは putpixeldata または次の画素操作の
    時点になりましたが、読み出しの直前に必ず反映されるため、観測できる結果は変わり
    ません。
  • ネイティブ実行環境が無い場合は、従来どおり MoonSharp で実行します。

内部実装

  • 転送の契約を PixelRegionAccess へ統一し、LuaJitWorker と PixelBufferManager を
    ポインタで直結しました。ワーカーが報告する結果寸法は共有メモリの容量で検査し、
    アップロード中に例外が起きた場合はワーカーを破棄して次回の実行で再起動します。
  • NativeProtocol へ draw リング領域とスクリプト版数のヘッダを追加しました。リングは
    1 件 24 個の倍精度値で 4096 件です。
  • worker.lua が getpixeldata の平坦な配列と遅延反映、リングへの書き溜めを行います。
  • SimdKernelCompiler が式木から Vector256 のブロック委譲を生成し、CpuKernel が
    4 画素単位のブロックと端数のスカラ処理を組み合わせます。ClampByte は Math.Clamp の
    分岐順序を ConditionalSelect で再現し、byte への変換もスカラと同一です。
  • CpuKernel の自己校正は、経路ごとに暖機 1 回と計測 3 回を交互に行い、累積時間の
    短い経路を採用します。判定はカーネルのインスタンスごとに一度だけ行い、以後は
    分岐しません。
  • KernelExtractor が getpixeldata の添字ループの定型を認識します。
  • テストは 3041 件です。v1.11.4 の 2994 件から、リングの順序と容量、遅延反映の整合、
    SIMD とスカラの一致、採用判定の収束と交互計測、抽出の拒否、転送領域の容量保証
    などの検証を追加しました。
    Direct2D の実描画を伴う直結転送の最終確認は、従来の GPU 経路と同様に YMM4 上が
    対象です。

v1.11.4

Choose a tag to compare

@github-actions github-actions released this 02 Jul 05:00

v1.11.4 - Lua スクリプト for YMM4

毎ピクセル処理のスクリプト(カーネル)の実行先を、GPU と CPU から自動で選べるように
したリリースです。これまで GPU カーネルは --!gpu を明示したときだけ使っていましたが、
指定が無いときも利用できるかを自動で判断し、利用できる場合は GPU で実行します。正確性を
最優先し、初回に実機の GPU で CPU カーネルとの出力一致を検証し、許容差に収まった
プログラムだけ GPU で実行します。あわせて、GPU カーネルと CPU カーネルで食い違って
いた HLSL の座標原点と出力の丸めを、CPU カーネルに合わせて修正しました。


改善

1. カーネルの GPU/CPU 自動選択

これまで毎ピクセル処理のスクリプトは、--!gpu を明示したときだけ GPU カーネルで実行し、
指定が無いときは CPU カーネルで実行していました。本リリースでは、指定が無いときも
GPU カーネルを利用できるかを自動で判断し、利用できる場合は GPU で実行します。GPU
カーネルは CPU カーネルが必要とするピクセルの読み戻しとアップロードを伴わないため、
そのぶん高速です。実行先はプログラム単位で一度だけ決まり、フレームや画像サイズによって
切り替わらないため、途中で結果がちらつくことはありません。

2. 実行時のセルフ検証で正確性を担保

GPU カーネルを初めて構築したとき、固定の 64×64 の検証用画像を実機の GPU で処理し、
その結果を CPU カーネルの結果と比較します。全チャンネルの差が許容範囲に収まった
プログラムだけを GPU で実行し、収まらない場合や検証を実行できない場合は CPU カーネルで
実行します。GPU の出力が CPU カーネルと食い違うことはありません。検証の結果はログに
記録します。


不具合修正

GPU カーネルの座標原点のずれを修正

GPU カーネルの HLSL は、ピクセル座標を「テクスチャ座標 × 寸法」で求めていました。
テクスチャ座標はピクセルの中心を指すため、求まる座標は CPU カーネルが用いる整数の
添字より 0.5 大きく、ループ変数 xy を参照するスクリプトで結果がずれていました。
テクスチャ座標から 0.5 を引くように変更し、CPU カーネルの整数座標と一致させました。

GPU カーネルの出力の丸めを修正

Direct2D は出力を四捨五入で 8 ビットへ量子化する一方、CPU カーネルは切り捨てていた
ため、両者に系統的な 1 階調のずれがありました。シェーダ側で各チャンネルを切り捨てて
から量子化するように変更し、丸め方を CPU カーネルへ統一しました。


互換性・後方互換

  • スクリプトの書き方と API に変更はありません。
  • --!cpu は従来どおり CPU カーネルで実行します。--!gpu は GPU カーネルで実行しますが、
    検証に通らない場合は CPU カーネルへ切り替え、一度だけ警告を記録します。
  • 指定の無いカーネルは、検証に通れば GPU、通らなければ CPU で実行します。いずれも
    出力は CPU カーネルと許容差の範囲で一致します。
  • GPU カーネルは浮動小数点で計算するため、CPU カーネルと 1 階調程度異なることが
    あります。この差が許容範囲に収まることを検証で確認したプログラムだけを GPU で
    実行します。
  • GPU を利用できない環境では、従来どおり CPU カーネルで実行します。

内部実装

  • HlslKernelEmitter の座標を「テクスチャ座標 × 寸法 - 0.5」へ、出力の各チャンネルを
    floor(clamp(...)) へ変更し、CPU カーネルの整数座標と切り捨てへ揃えました。
  • GpuKernelVerify を追加しました。検証用画像を効果で描画して読み戻し、
    CpuKernel の結果と比較します。差が許容範囲に収まらない場合は GPU カーネルを
    採用しません。
  • LuaScriptEffectProcessorGetGpuKernel は検証に通った GPU カーネルだけを返し、
    判定をプログラム単位でキャッシュします。ExecuteKernelLane は指定が無いときと
    --!gpu のときに検証済みの GPU カーネルを優先し、無ければ CPU カーネルで実行します。
  • テストへ HLSL の座標原点と出力の丸めを検証するケースを追加しました(全 2994 件)。
    GPU カーネルの実行と検証は実機の GPU が必要なため、YMM4 上での確認が対象です。

v1.11.3

Choose a tag to compare

@github-actions github-actions released this 02 Jul 04:21

v1.11.3 - Lua スクリプト for YMM4

v1.11.2 で GPU 実行へ切り替えた tempbuffer への描画合成について、実行時の安定性を高め、
GPU 描画経路のリソースの後始末を整えたリリースです。GPU 合成をピクセルの読み出しと同じ
セマフォで直列化し、スクリプトのタイムアウトで破棄されたワーカースレッドの合成が後続
フレームと競合しないようにしました。あわせて、合成の契約をコマンド単位で委譲できる形へ
変更し、GPU で扱える寸法の上限を超えるバッファはそのコマンドだけ CPU 合成で処理する
ようにしました。さらに、GPU 描画経路で毎フレーム発生していたネイティブ参照の漏れを
解消しました。


改善

1. GPU 合成のスレッド安全性を強化

GPU での tempbuffer 合成を、ピクセルの読み出しと同じセマフォで直列化しました。
MoonSharp のスクリプトは専用のワーカースレッドで実行されるため、実行時間が上限を
超えてタイムアウトが発生すると、そのスレッドは破棄されて次回実行時に新しいスレッドが
生成されます。破棄されたスレッドに実行中の GPU 合成が残っていても、後続フレームの
DeviceContext の利用と競合しないようにしました。

2. GPU の上限を超えるバッファをコマンド単位で CPU 合成へ

GPU で扱える寸法の上限を超える合成は、そのコマンドだけ従来の CPU 合成で処理する
ようにしました。上限を超えたことを理由に GPU 合成全体が無効化されることはありません。
上限以下のサイズの後続コマンドは、引き続き GPU で合成します。


不具合修正

GPU 描画経路のネイティブ参照の漏れを解消

Vortice の TargetOutput のゲッターは、呼び出しのたびに参照数を増やした新しい
ラッパーを返します。従来はこのラッパーを毎フレーム生成したまま破棄しておらず、ネイティブ
の参照が少しずつ漏れていました。取得した Target を復元後に破棄し、効果の Output
生成時に一度だけ取得してキャッシュするように変更して、毎フレームのラッパー生成と
ネイティブ参照の漏れを無くしました。長時間のレンダリングでのメモリの使用が安定します。


互換性・後方互換

  • スクリプトの書き方と API に変更はありません。drawtarget の指定方法と描画結果の
    意味論は従来どおりです。
  • GPU を利用できない環境では、従来と同じ CPU 合成で動作します。
  • GPU で扱える寸法の上限を超える tempbuffer への合成は CPU 合成で処理し、結果は
    従来の CPU 合成と同じになります。
  • GPU 合成は浮動小数点で丸めるため、tempbuffer への合成結果が CPU 合成と 1 階調程度
    異なることがあります。ネイティブエンジンの tempbuffer 合成は従来どおりワーカー内の
    CPU で実行されるため、丸めの違いによりエンジン間で合成結果がごく僅かに異なることが
    あります。
  • framebuffer への描画合成は従来どおり GPU で実行され、意味論に変更はありません。

内部実装

  • 合成の契約 IBufferCompositorComposeTryCompose へ変更しました。合成器が
    処理を引き受けなかったときは false を返し、AviUtlScriptContext
    FallbackCompositor はコマンド単位で次の合成器へ委ねます。
  • SynchronizedCompositor を追加しました。内側の合成器の呼び出しを、指定した
    セマフォで直列化します。LuaScriptEffectProcessorHardwareCompositor
    ピクセル読み出し用のセマフォで包み、GPU 合成とピクセルの読み出しが同じ
    DeviceContext を同時に触らないようにしました。
  • HardwareCompositor へ寸法の上限 8192 を設け、合成元と合成先のいずれかがこれを
    超える場合は処理を引き受けずに false を返すようにしました。
  • FallbackCompositor は、GPU の合成器が例外を投げたときだけ CPU の合成器へ恒久的に
    降格し、通知コールバックを一度だけ呼び出します。合成器が処理を引き受けずに false
    を返した場合は降格として扱わず、そのコマンドだけ CPU 合成へ委ねます。
  • SoftwareCompositor を静的クラスから共有インスタンス SoftwareCompositor.Instance
    へ変更しました。合成の数学に変更はありません。
  • Vortice の TargetOutput のゲッターがラッパーを都度生成する問題へ対応しました。
    HardwareCompositorDrawCompositorPixelBufferManager は取得した Target
    復元後に破棄し、DrawCompositorPixelBufferManagerGpuKernel は効果の Output
    を生成時に一度だけ取得してキャッシュします。
  • テストへ SynchronizedCompositorTests を追加し、FallbackCompositor の引き受け拒否
    の経路と SoftwareCompositorTryCompose ディスパッチの検証を加えました
    (全 2992 件)。HardwareCompositor の描画出力はテスト環境で Direct2D を実行できない
    ため、YMM4 上での確認が対象です。

v1.11.2

Choose a tag to compare

@github-actions github-actions released this 02 Jul 04:08

v1.11.2 - Lua スクリプト for YMM4

tempbuffer への描画合成を GPU 実行へ置き換えたリリースです。MoonSharp エンジンで
obj.draw / obj.drawpolytempbuffer へ行う合成を、CPU のピクセルループから
Direct2D による GPU 合成へ変更しました。GPU を利用できない環境では従来の CPU 合成へ
自動的に切り替わります。あわせて、描画合成の変換行列の計算を一元化し、合成レーンの
ユニットテストを追加しました。


新機能・機能改善

1. tempbuffer への描画合成を GPU 実行へ変更

MoonSharp エンジンで obj.setoption("drawtarget", "tempbuffer") を指定した際の
obj.draw / obj.drawpoly の合成を、GPU で実行するようにしました。

  • 合成の意味論は従来と同一です。乗算済みアルファのソースオーバー、不透明度の乗算、
    antialias によるリニア・ニアレストの切り替えをそのまま維持しています。
  • GPU での合成に失敗した場合は従来の CPU 合成へ自動的に切り替わり、ログへ一度だけ
    警告を出します。切り替え後の動作は従来と完全に同じです。
  • 大きな tempbuffer へ繰り返し合成するスクリプトで、毎フレームの CPU 負荷が
    下がります。

2. 描画合成の変換行列を一元化

obj.draw の ox / oy / zoom / aspect と obj.drawpoly の 4 頂点から合成の変換行列を
求める処理を 1 箇所へ集約し、framebuffer への合成と tempbuffer への合成が同じ
定義を共有するようにしました。拡大率が 0 になる描画コマンドは、どちらの描画先でも
合成をスキップします。

3. ドキュメントの更新

内蔵ドキュメント(LuaScript/docs/LuaScript.*.txt)・README・サイトのドキュメントへ、
tempbuffer への合成が MoonSharp では GPU で実行されることと、GPU を利用できない
環境では CPU の合成へ自動的に切り替わることを各言語で追記しました。


互換性・後方互換

  • スクリプトの書き方と API に変更はありません。drawtarget の指定方法・描画結果の
    意味論は従来どおりです。
  • GPU を利用できない環境では、従来と同じ CPU 合成で動作します。
  • GPU 合成は浮動小数点で丸めるため、tempbuffer への合成結果が従来の CPU 合成と
    1 階調程度異なることがあります。ネイティブエンジンの tempbuffer 合成は従来どおり
    ワーカー内の CPU で実行されるため、丸めの違いによりエンジン間で合成結果がごく僅かに
    異なることがあります。
  • framebuffer への描画合成は従来どおり GPU で実行され、変更はありません。

内部実装

  • 合成の契約 IBufferCompositor を追加し、AviUtlScriptContexttempbuffer 合成が
    注入された合成器を使うようにしました。既定は CPU の SoftwareCompositor で、
    ネイティブレーンとテストの動作は変わりません。
  • HardwareCompositor を追加しました。PixelBufferManager と同じ手順で、合成元と
    合成先のアップロード、ソースオーバーでの描画、CPU 読み取り可能なステージング
    ビットマップ経由の読み戻しを行います。ビットマップはサイズ単位でキャッシュします。
  • FallbackCompositor を追加しました。GPU の合成器を優先し、初回の例外で恒久的に
    CPU の合成器へ降格して、通知コールバックを一度だけ呼び出します。
  • SoftwareCompositor を静的クラスからインスタンスクラスへ変更し、既存の合成処理を
    そのまま契約の実装として保持しました。合成の数学に変更はありません。
  • 変換行列の構築を DrawTransform.TryResolve へ集約し、DrawCompositor
    HardwareCompositor の双方が同じ数学を共有するようにしました。
  • LuaScriptEffectProcessorCreateEffect とタイムアウト後のコンテキスト再生成で
    合成器を注入するようにしました。
  • テストへ DrawTransformTestsFallbackCompositorTests と、SoftwareCompositor
    Compose ディスパッチの検証を追加しました(全 2987 件)。HardwareCompositor
    描画出力はテスト環境で Direct2D を実行できないため、YMM4 上での確認が対象です。