共有メモリ機能
自作のUE4用ライブラリObjectDelivererに共有メモリプロトコルを追加実装しました。
これにより、従来から実装済みのTCP/IP, UDPに加えて共有メモリを使ったデータ転送が行えます。 ただし共有メモリはWindows Onlyです。。。
使い方
ObjectDelivererのプロトコルとして実装してあるため、ObjectDelivererManagerのStartメソッドに渡すプロトコルを切り替えるだけで使用できます。
deliverer->Start(UProtocolFactory::CreateProtocolSharedMemory("memory_test", 1024),
UPacketRuleFactory::CreatePacketRuleSizeBody());
CreateProtocolSharedMemoryには共有メモリ名とメモリサイズを渡します。 この2つはデータのやり取りを行う相手と同じ値である必要があります。
仕様
データの送受信プロトコルとして使うため、作成した共有メモリの中身は定期的にポーリングしています。 ただし毎回データアクセスを行うと処理負荷が上がるため、以下のような仕組みで対応しています。
定期的なポーリング時はまず共有メモリの先頭1byteを読み込んで、前回読み込み時とカウンタの値が異なっているかをチェックします。
異なっていれば新しいデータが書き込まれていると判断して、次の4byteを読み込みデータサイズを確認した後データ本体を読み込みます。
そのためObjectDelivererを使ってないプロセスと共有メモリを使ったやり取りをする場合は、この仕様に合わせる必要があります。
サンプル
今回作成した共有メモリプロトコルを使って、以下のムービーのようなサンプルを作りました。
ObjectDelivererの共有メモリのテスト題材作成中。
— ayuma (@ayuma_x) January 29, 2019
WPFアプリが毎フレーム自分のウィンドウを共有メモリに書き込んで、それをUE4側が読み込みテクスチャを更新してる。#ObjectDeliverer #UE4 #UE4Study pic.twitter.com/uWY2QhHnYP
WPFで作ったアプリケーションに毎フレーム自分のウィンドウの表示内容を共有メモリに書き込ませ、UE4側ではObjectDelivererを使ってデータを受信します。
受信したデータ(ピクセルバッファ)を使ってテクスチャの中身を更新して、UE4の表示側をWPF側にミラーリングしています。
共有メモリのため同じマシンに2つのアプリケーションがないと使えませんが、パッと見た感じ遅延もなく同期できています。
参考までにここで作成したWPFアプリは↓です。
課題
長時間上記ミラーリングしていると共有メモリの読み込み時にUObject::ProcessEventの!IsUnreachable()のチェックにひっかかり落ちてしまう現象がでちゃってます。
これが治らないと使えないなー。
暫定ですが、BlueprintNativeEventを使っているところを全て取り除くことで治りました。 ただしこれではBlueprintでオーバーライドできなくなるので、そのあたりまた検討します。