UE4 ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER 宏

該宏非常重要, 其作用是: 創建一個渲染命令任務,並將該任務壓入渲染隊列,待渲染線程執行. 主要用於多線程渲染!

#define ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(TypeName,ParamType1,ParamName1,ParamValue1,Code) 

等效於下面兩個宏:

#define ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER_DECLARE_OPTTYPENAME(TypeName,ParamType1,ParamName1,ParamValue1,OptTypename,Code) \
    class EURCMacro_##TypeName : public FRenderCommand \
    { \
    public: \
        EURCMacro_##TypeName(OptTypename TCallTraits<ParamType1>::ParamType In##ParamName1): \
          ParamName1(In##ParamName1) \
        {} \
        TASK_FUNCTION(Code) \
        TASKNAME_FUNCTION(TypeName) \
    private: \
        ParamType1 ParamName1; \
    };

#define ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER_CREATE(TypeName,ParamType1,ParamValue1) \
    { \
        if(GIsThreadedRendering || !IsInGameThread()) \
        { \
            CheckNotBlockedOnRenderThread(); \            
            TGraphTask<EURCMacro_##TypeName>::CreateTask().ConstructAndDispatchWhenReady(ParamValue1); \ 
        } \
        else \
        { \
            EURCMacro_##TypeName TempCommand(ParamValue1); \
            FScopeCycleCounter EURCMacro_Scope(TempCommand.GetStatId()); \
            TempCommand.DoTask(ENamedThreads::GameThread, FGraphEventRef() ); \
        } \
    }

示例代碼:

ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
        BeginDrawingCommand,
        FViewport*,Viewport,this,
    {
        Viewport->BeginRenderFrame(RHICmdList);
    });

以上代碼展開宏之後如下:

class EURCMacroBeginDrawingCommand : public FRenderCommand 
    { 
    public: 
        EURCMacroBeginDrawingCommand(OptTypename TCallTraits<ParamType1>::ParamType InViewport): 
          Viewport(InViewport) 
        {} 
        TASK_FUNCTION(Code) 
        TASKNAME_FUNCTION(TypeName) 
    private: 
        FViewport*  Viewport; 
    };

   {
        if(GIsThreadedRendering || !IsInGameThread()) 
        { 
            CheckNotBlockedOnRenderThread(); 
            //創建一個渲染任務,並壓入渲染隊列,之後由渲染線程執行           
            TGraphTask<EURCMacroBeginDrawingCommand>::CreateTask().ConstructAndDispatchWhenReady(this);  
        } 
        else 
        {   
            //直接由主線程立刻執行
            EURCMacroBeginDrawingCommand TempCommand(this); 
            FScopeCycleCounter EURCMacro_Scope(TempCommand.GetStatId()); 
            TempCommand.DoTask(ENamedThreads::GameThread, FGraphEventRef() ); 
        } 
   }


TASK_FUNCTION(Code)宏定義了DoTask方法,該方法就是任務的具體執行內容,而Code對應了上面例子的Viewport->BeginRenderFrame(RHICmdList);

#define TASK_FUNCTION(Code) \
        void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) \
        { \
            FRHICommandListImmediate& RHICmdList = GetImmediateCommandList_ForRenderCommand(); \
            Code; \
        }

而任務的DoTask方法是如何被執行的,就要去ConstructAndDispatchWhenReady裏找答案了,展開篇幅太長,有空再研究!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章