UE4/C++, Blueprint: UAsyncTaskDownloadImage を拡張した実装を使いたい場合にリンクが必要となる RHI と RenderCore のメモ
状況
UAsyncTaskDownloadImage
はブループリントでは癖の強めの非同期処理ノード。何かを For
などでループしながら DownloadImage
ノードを使い OnSuccess
にテクスチャーデータだけでなく何らかのインデックスなどの付加情報を引っ掛けた処理を行わせようとすると、結果的にはループの最後の状態の値が非同期処理の実行時には採用され、意図しない処理結果となる事がある。
例えば次のような具合のノードをブループリントで組んだ場合、
DownloadImage
ノードの左側の同期処理される赤文字出力の PrintText
では 1
, 2
, 3
, ... が出力されるが、 DownloadImage
ノードの右側の非同期処理されえる青文字出力の PrintText
では 8
, 8
, 8
, ... が出力される。内部的に IHttpRequest
の非同期処理を使うため DownloadImage
の OnSuccess
あるいは OnFail
デリゲートのブロードキャストから実行される非同期処理の実行時には ForLoop
は完了した最後の状態で Index
は 8
になっている。( DownloadImage
実行時にその後の非同期処理で必要になる変数をキャプチャーしてくれる機能は無いが、ブループリントの実装都合 Index
が未定義で落ちる事は無い。 )
そこで、必要に応じた変数のキャプチャーと通知の機能を仕込んだ UAsyncTaskDownloadImage
の拡張を実装したくなる。幸い UE4 はオープンソースソフトウェアで実装を自分のプロジェクトへコピー&ペーストして、必要に応じて UAsyncTaskDownloadImageMyCustom
などクラス名を変え、DownloadImage
関数の引数にキャプチャーしたい変数を追加しメンバー変数として保持しつつ、 OnSuccess
あるいは OnFail
デリゲートの定義を DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams
など使って必要なだけ引数を拡張し、それらのデリゲートの Broadcast
の呼び出し時にメンバー変数へ保持しておいた値を実引数として与えるようにすればよい。
よい、のじゃが、これだけだとビルドできない。たぶん↓のようなリンクエラーに襲われる事になる。
CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static bool __cdecl FRHIResource::Bypass(void)" (__imp_?Bypass@FRHIResource@@SA_NXZ) referenced in function "void __cdecl WriteRawToTexture_RenderThread(class FTexture2DDynamicResource *,class TArray<unsigned char,class FDefaultA llocator> const &,bool)" (?WriteRawToTexture_RenderThread@@YAXPEAVFTexture2DDynamicResource@@AEBV?$TArray@EVFDefaultAllocator@@@@_N@Z) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: unsigned int __cdecl FRHITexture2D::GetSizeX(void)const " (__imp_?GetSizeX@FRHITexture2D@@QEBAIXZ) referenced in function "void __cdecl WriteRawToTexture_RenderThread(class FTexture2DDynamicResource *,class TArray<unsigned char,c lass FDefaultAllocator> const &,bool)" (?WriteRawToTexture_RenderThread@@YAXPEAVFTexture2DDynamicResource@@AEBV?$TArray@EVFDefaultAllocator@@@@_N@Z) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: unsigned int __cdecl FRHITexture2D::GetSizeY(void)const " (__imp_?GetSizeY@FRHITexture2D@@QEBAIXZ) referenced in function "void __cdecl WriteRawToTexture_RenderThread(class FTexture2DDynamicResource *,class TArray<unsigned char,c lass FDefaultAllocator> const &,bool)" (?WriteRawToTexture_RenderThread@@YAXPEAVFTexture2DDynamicResource@@AEBV?$TArray@EVFDefaultAllocator@@@@_N@Z) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static enum ENamedThreads::Type __cdecl FRenderCommand::GetDesiredThread(void)" (__imp_?GetDesiredThread@FRenderCommand@@SA?AW4Type@ENamedThreads@@XZ) referenced in function "private: void __cdecl TGraphTask<class `private: void __cdecl UAsyncTaskDownloadMap::HandleMapRequest(class TSharedPtr<class IHttpRequest,0>,class TSharedPtr<class IHttpResponse,1>,bool)'::`16'::EURCMacro_FWriteRawDataToTexture>::SetupPrereqs(class TArray<class TRefCountPtr<class FGraphEvent>,class TInlineAllocator<4,class FDefaultAllocator> > const *,enum ENamedThreads::Type,bool)" (?SetupPrereqs@?$TGraphTask@ VEURCMacro_FWriteRawDataToTexture@?BA@??HandleMapRequest@UAsyncTaskDownloadMap@@AEAAXV?$TSharedPtr@VIHttpRequest@@$0A@@@V?$TSharedPtr@VIHttpResponse@@$00@@_N@Z@@@AEAAXPEBV?$TArray@V?$TRefCountPtr@VFGraphEvent@@@@V?$TInlineAllocator@$03VFDefaultAllocator@@@@@@W4Type@ENamedThreads@@_N@Z) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static enum ESubsequentsMode::Type __cdecl FRenderCommand::GetSubsequentsMode(void)" (__imp_?GetSubsequentsMode@FRenderCommand@@SA?AW4Type@ESubsequentsMode@@XZ) referenced in function "public: static class TGraphTask<class `priva te: void __cdecl UAsyncTaskDownloadMap::HandleMapRequest(class TSharedPtr<class IHttpRequest,0>,class TSharedPtr<class IHttpResponse,1>,bool)'::`16'::EURCMacro_FWriteRawDataToTexture>::FConstructor __cdecl TGraphTask<class `private: void __cdecl UAsyncTaskDownloadMap::HandleMapRequest(class TSharedPtr<class IHttpRequest,0>,class TSharedPtr<class IHttpRespons e,1>,bool)'::`16'::EURCMacro_FWriteRawDataToTexture>::CreateTask(class TArray<class TRefCountPtr<class FGraphEvent>,class TInlineAllocator<4,class FDefaultAllocator> > const *,enum ENamedThreads::Type)" (?CreateTask@?$TGraphTask@VEURCMacro_FWriteRawDataToTexture@?BA@??HandleMapRequest@UAsyncTaskDownloadMap@@AEAAXV?$TSharedPtr@VIHttpRequest@@$0A@@@V?$TSharedP tr@VIHttpResponse@@$00@@_N@Z@@@SA?AVFConstructor@1@PEBV?$TArray@V?$TRefCountPtr@VFGraphEvent@@@@V?$TInlineAllocator@$03VFDefaultAllocator@@@@@@W4Type@ENamedThreads@@@Z) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) class FRHICommandListImmediate & __cdecl GetImmediateCommandList_ForRenderCommand(void)" (__imp_?GetImmediateCommandList_ForRenderCommand@@YAAEAVFRHICommandListImmediate@@XZ) referenced in function "private: virtual void __cdecl TGraphTa sk<class `private: void __cdecl UAsyncTaskDownloadMap::HandleMapRequest(class TSharedPtr<class IHttpRequest,0>,class TSharedPtr<class IHttpResponse,1>,bool)'::`16'::EURCMacro_FWriteRawDataToTexture>::ExecuteTask(class TArray<class FBaseGraphTask *,class FDefaultAllocator> &,enum ENamedThreads::Type)" (?ExecuteTask@?$TGraphTask@VEURCMacro_FWriteRawDataToTextu re@?BA@??HandleMapRequest@UAsyncTaskDownloadMap@@AEAAXV?$TSharedPtr@VIHttpRequest@@$0A@@@V?$TSharedPtr@VIHttpResponse@@$00@@_N@Z@@@EEAAXAEAV?$TArray@PEAVFBaseGraphTask@@VFDefaultAllocator@@@@W4Type@ENamedThreads@@@Z) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) bool GRHINeedsExtraDeletionLatency" (__imp_?GRHINeedsExtraDeletionLatency@@3_NA) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) private: static class TLockFreePointerListUnordered<class FRHIResource,128> FRHIResource::PendingDeletes" (__imp_?PendingDeletes@FRHIResource@@0V?$TLockFreePointerListUnordered@VFRHIResource@@$0IA@@@A) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) class FDynamicRHI * GDynamicRHI" (__imp_?GDynamicRHI@@3PEAVFDynamicRHI@@EA) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) class FRHICommandListExecutor GRHICommandList" (__imp_?GRHICommandList@@3VFRHICommandListExecutor@@A) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) bool GIsThreadedRendering" (__imp_?GIsThreadedRendering@@3_NA) CompilerResultsLog: Error: AsyncTaskDownloadMap.cpp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) class TAtomic<bool> GMainThreadBlockedOnRenderThread" (__imp_?GMainThreadBlockedOnRenderThread@@3V?$TAtomic@_N@@A)
リンクエラーの解消法
MyProjeect.Build.cs
の PublicDependencyModuleNames
に RHI
とRenderCore
を追加する。
PublicDependencyModuleNames.AddRange ( new string[] { "RHI", "RenderCore"
ちなみに、 RHI は Rendering Hardware Interface の事らしい。プラットフォームごとに D3D, OGL などを抽象化したレンダリングハードウェアのインターフェースらしいが、私もその実装まではまだ確認していない。