<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      智慧 + 毅力 = 無所不能

      正確性、健壯性、可靠性、效率、易用性、可讀性、可復用性、兼容性、可移植性...

      導航

      UE4 引擎剖析 - 渲染線程

      Posted on 2020-07-15 12:19  Bill Yuan  閱讀(2173)  評論(0)    收藏  舉報

      轉自:https://zhuanlan.zhihu.com/p/78347351

      一、渲染線程的初始化:

      //////////////////////////////////////////////////////////////////////////////////////////////
      // 渲染線程執行體
      class FRenderingThread : public FRunnable
      {
        // 執行函數
        virtual uint32 Run(void) override
        {
          RenderingThreadMain( TaskGraphBoundSyncEvent );
        }
      }
      //////////////////////////////////////////////////////////////////////////////////////////////
      // 渲染線程初始化流程:
      1. FEngineLoop::PreInit()
      {
          StartRenderingThread()
      }
      2. StartRenderingThread()
      {
          GRenderingThreadRunnable = new FRenderingThread()
          GRenderingThread = FRunnableThread::Create(GRenderingThreadRunnable, ...)
      }

       

      二、渲染線程的執行:(基于UE4的任務圖系統: FTaskGraphInterface)

      //////////////////////////////////////////////////////////////////////////////////////////////
      // 任務圖系統: 線程基類
      class FTaskThreadBase : public FRunnable, FSingleThreadRunnable
      {
          protected:
          /** Id / Index of this thread. **/
          ENamedThreads::Type ThreadId;
          /** Array of tasks for this task thread. */
          TArray<FBaseGraphTask*> NewTasks;
          /** back pointer to the owning FWorkerThread **/
          FWorkerThread* OwnerWorker;
      }
      // 任務圖系統: 任意線程類
      class FTaskThreadAnyThread : public FTaskThreadBase
      
      //...
          virtual void ProcessTasksUntilQuit(int32 QueueIndex) override
          {
              check(Queue(QueueIndex).StallRestartEvent); // make sure we are started up
      
              Queue(QueueIndex).QuitForReturn = false;
              verify(++Queue(QueueIndex).RecursionGuard == 1);
              do
              {
                  ProcessTasksNamedThread(QueueIndex, FPlatformProcess::SupportsMultithreading());
              } while (!Queue(QueueIndex).QuitForReturn && !Queue(QueueIndex).QuitForShutdown && FPlatformProcess::SupportsMultithreading()); // @Hack - quit now when running with only one thread.
              verify(!--Queue(QueueIndex).RecursionGuard);
          }
      
      //...
          /**
          *    Process tasks until idle. May block if bAllowStall is true
          *    @param QueueIndex, Queue to process tasks from
          *    @param bAllowStall,  if true, the thread will block on the stall event when it runs out of tasks.
          **/
          uint64 ProcessTasks()
          {
              LLM_SCOPE(ELLMTag::TaskGraphTasksMisc);
      
              TStatId StallStatId;
              bool bCountAsStall = true;
              uint64 ProcessedTasks = 0;
      #if STATS
              TStatId StatName;
              FCycleCounter ProcessingTasks;
              StatName = GET_STATID(STAT_TaskGraph_OtherTasks);
              StallStatId = GET_STATID(STAT_TaskGraph_OtherStalls);
              bool bTasksOpen = false;
              if (FThreadStats::IsCollectingData(StatName))
              {
                  bTasksOpen = true;
                  ProcessingTasks.Start(StatName);
              }
      #endif
              verify(++Queue.RecursionGuard == 1);
              bool bDidStall = false;
              while (1)
              {
                  FBaseGraphTask* Task = FindWork();
                  if (!Task)
                  {
      #if STATS
                      if (bTasksOpen)
                      {
                          ProcessingTasks.Stop();
                          bTasksOpen = false;
                      }
      #endif
      
                      TestRandomizedThreads();
                      if (FPlatformProcess::SupportsMultithreading())
                      {
                          FScopeCycleCounter Scope(StallStatId);
                          Queue.StallRestartEvent->Wait(MAX_uint32, bCountAsStall);
                          bDidStall = true;
                      }
                      if (Queue.QuitForShutdown || !FPlatformProcess::SupportsMultithreading())
                      {
                          break;
                      }
                      TestRandomizedThreads();
      
      #if STATS
                      if (FThreadStats::IsCollectingData(StatName))
                      {
                          bTasksOpen = true;
                          ProcessingTasks.Start(StatName);
                      }
      #endif
                      continue;
                  }
                  TestRandomizedThreads();
      #if YIELD_BETWEEN_TASKS
                  // the Win scheduler is ill behaved and will sometimes let BG tasks run even when other tasks are ready....kick the scheduler between tasks
                  if (!bDidStall && PriorityIndex == (ENamedThreads::BackgroundThreadPriority >> ENamedThreads::ThreadPriorityShift))
                  {
                      FPlatformProcess::Sleep(0);
                  }
      #endif
                  bDidStall = false;
                  Task->Execute(NewTasks, ENamedThreads::Type(ThreadId));
                  ProcessedTasks++;
                  TestRandomizedThreads();
                  if (Queue.bStallForTuning)
                  {
      #if STATS
                      if (bTasksOpen)
                      {
                          ProcessingTasks.Stop();
                          bTasksOpen = false;
                      }
      #endif
                      {
                          FScopeLock Lock(&Queue.StallForTuning);
                      }
      #if STATS
                      if (FThreadStats::IsCollectingData(StatName))
                      {
                          bTasksOpen = true;
                          ProcessingTasks.Start(StatName);
                      }
      #endif
                  }
              }
              verify(!--Queue.RecursionGuard);
              return ProcessedTasks;
          }

       

      //////////////////////////////////////////////////////////////////////////////////////////////
      // 渲染線程的執行流程:
      1. uint32 FRenderingThread::Run(void)
      {
          RenderingThreadMain( TaskGraphBoundSyncEvent );
      }
      
      2. void RenderingThreadMain( FEvent* TaskGraphBoundSyncEvent )
      {
          // 任務圖系統: 將渲染線程設置為的當前線程
          FTaskGraphInterface::Get().AttachToThread(RenderThread);
      
          // 任務圖系統: 執行當前線程
          FTaskGraphInterface::Get().ProcessThreadUntilRequestReturn(RenderThread);
      }
      
      3. void FTaskGraphImplementation::AttachToThread(ENamedThreads::Type CurrentThread)
      {
          CurrentThread = ENamedThreads::GetThreadIndex(CurrentThread);
          check(NumTaskThreadsPerSet);
          check(CurrentThread >= 0 && CurrentThread < NumNamedThreads);
          check(!WorkerThreads[CurrentThread].bAttached);
          Thread(CurrentThread).InitializeForCurrentThread();
      }
      
      4. void FTaskGraphImplementation::ProcessThreadUntilRequestReturn(ENamedThreads::Type CurrentThread)
      {
          int32 QueueIndex = ENamedThreads::GetQueueIndex(CurrentThread);
          CurrentThread = ENamedThreads::GetThreadIndex(CurrentThread);
          check(CurrentThread >= 0 && CurrentThread < NumNamedThreads);
          check(CurrentThread == GetCurrentThread());
          Thread(CurrentThread).ProcessTasksUntilQuit(QueueIndex);
      }
      
      5. void FTaskThreadAnyThread::ProcessTasksUntilQuit(int32 QueueIndex)
      {
          do
          {
              ProcessTasks();
          } while (!Queue.QuitForShutdown && FPlatformProcess::SupportsMultithreading()); // @Hack - quit now when     running with only one thread.
      }
      
      6. void FTaskThreadAnyThread::ProcessTasks()
      {
          while (1)
          {
              FBaseGraphTask* Task = FindWork();
              Task->Execute(NewTasks, ENamedThreads::Type(ThreadId));
          }
      }

       

      備注: FBaseGraphTask就是任務圖系統的執行的內容,參考:UE4 引擎剖析 - 多線程

      三、計算玩家的視圖信息。

      //////////////////////////////////////////////////////////////////////////////////////////////
      // 渲染目標
      class FRenderTarget
      {
          protected:
          FTexture2DRHIRef RenderTargetTextureRHI;
      }
      
      /**
      *封裝視區的I/O。
      *視區顯示是使用獨立于平臺的RHI實現的。
      */
      class FViewport : public FRenderTarget, protected FRenderResource
      {
      public:
          ENGINE_API void Draw( bool bShouldPresent = true );
      
      protected:
          /** The viewport's client. */
          FViewportClient* ViewportClient;
      }
      
      /**
      *到視區客戶機的抽象接口。
      *視區的客戶機處理視區接收到的輸入,并繪制視區。
      */
      class FViewportClient
      {
          public:
          virtual void Draw(FViewport* Viewport,FCanvas* Canvas) {}
      }
      
      /**
      *游戲視區(FViewport)是平臺特定的渲染、音頻和輸入子系統。
      *GameViewportClient是引擎與游戲視區的接口。
      *只為游戲的每個實例創建一個GameViewportClient。
      *唯一的例外是在編輯器(PIE)模式下,只有一個Engine引擎實例,但是有多個GameInstance游戲實例,則會創建多個GameViewportClients視區客戶端實例
      *職責:
      *將輸入事件傳播到全局交互列表
      */
      UCLASS(Within=Engine, transient, config=Engine)
      class ENGINE_API UGameViewportClient : public UScriptViewportClient, public FExec
      {
      public:
          virtual void Draw(FViewport* Viewport,FCanvas* SceneCanvas) override;
      
      public:
          /** The platform-specific viewport which this viewport client is attached to. */
          FViewport* Viewport;
      
      protected:
          /* The relative world context for this viewport */
          UPROPERTY()
          UWorld* World;
      
          UPROPERTY()
          UGameInstance* GameInstance;
      }
      
      /**
      * 將一組視圖轉換為只有不同視圖轉換和所有者參與者的場景。
      */
      class ENGINE_API FSceneViewFamily
      {
          /** The render target which the views are being rendered to. */
          FSceneInterface* Scene;
      }
      
      /**
      * 當視圖超出范圍時刪除其視圖的視圖族。
      */
      class FSceneViewFamilyContext : public FSceneViewFamily
      {
      }
      
      /**
      * 到場景的私有場景管理器實現的接口. 使用GetRendererModule().AllocateScene來創建.
      */
      class FSceneInterface
      {
          /**
          * 向場景中添加新的基本體組件
          */
          virtual void AddPrimitive(UPrimitiveComponent* Primitive) = 0;
      
          /**
          * 向場景中添加新的燈光組件
          */
          virtual void AddLight(ULightComponent* Light) = 0;
      
          /**
          * 將新貼花組件添加到場景中
          */
          virtual void AddDecal(UDecalComponent* Component) = 0;
      
          /**
          * 將新的指數高度霧組件添加到場景中
          */
          virtual void AddExponentialHeightFog(class UExponentialHeightFogComponent* FogComponent) = 0;
      
          /**
          * 向場景中添加新的大氣霧組件
          */
          virtual void AddAtmosphericFog(class UAtmosphericFogComponent* FogComponent) = 0;
      
          /**
          * 將風源組件添加到場景中。
          */
          virtual void AddWindSource(class UWindDirectionalSourceComponent* WindComponent) = 0;
      
          /**
          * 將SpeedTree風計算對象添加到場景中。
          */
          virtual void AddSpeedTreeWind(class FVertexFactory* VertexFactory, const class UStaticMesh* StaticMesh) = 0;
      }
      
      /**
      * 從場景空間到二維屏幕區域的投影。
      */
      class ENGINE_API FSceneView
      {
      public:
          const FSceneViewFamily* Family;
      
      public:
          FSceneViewInitOptions SceneViewInitOptions;
          FViewMatrices ViewMatrices;
          FViewMatrices ShadowViewMatrices;
      }
      
      // Projection data for a FSceneView
      struct FSceneViewProjectionData
      {
          /** The view origin. */
          FVector ViewOrigin;
      
          /** Rotation matrix transforming from world space to view space. */
          FMatrix ViewRotationMatrix;
      
          /** UE4 projection matrix projects such that clip space Z=1 is the near plane, and Z=0 is the infinite far plane. */
          FMatrix ProjectionMatrix;
      
      protected:
          //The unconstrained (no aspect ratio bars applied) view rectangle (also unscaled)
          FIntRect ViewRect;
      
          // The constrained view rectangle (identical to UnconstrainedUnscaledViewRect if aspect ratio is not constrained)
          FIntRect ConstrainedViewRect;
      }
      
      // Construction parameters for a FSceneView
      struct FSceneViewInitOptions : public FSceneViewProjectionData
      {
      }
      
      struct FViewMatrices
      {
          // 渲染的基礎矩陣
          FMatrix ViewProjectionMatrix;
      }

       

      //////////////////////////////////////////////////////////////////////////////////////////////
      // 主線程計算玩家的視圖信息流程:
      1. void FEngineLoop::Tick()
      {
          GEngine->Tick(FApp::GetDeltaTime(), bIdleMode);
      }
      
      2. void UGameEngine::Tick( float DeltaSeconds, bool bIdleMode )
      {
          UGameEngine::RedrawViewports()
      }
      
      3. void UGameEngine::RedrawViewports( bool bShouldPresent /*= true*/ )
      {
          if ( GameViewport != NULL )
          {
              if ( GameViewport->Viewport != NULL )
              {
                  GameViewport->Viewport->Draw(bShouldPresent);
              }
          }
      }
      
      4. void FViewport::Draw( bool bShouldPresent /*= true */)
      {
          UWorld* ViewportWorld = ViewportClient->GetWorld();
          FCanvas Canvas(this, nullptr, ViewportWorld, ViewportWorld ? ViewportWorld->FeatureLevel : GMaxRHIFeatureLevel, FCanvas::CDM_DeferDrawing, ViewportClient->ShouldDPIScaleSceneCanvas() ? ViewportClient->GetDPIScale() : 1.0f);
          Canvas.SetRenderTargetRect(FIntRect(0, 0, SizeX, SizeY));
          {
              // Make sure the Canvas is not rendered upside down
              Canvas.SetAllowSwitchVerticalAxis(false);
              ViewportClient->Draw(this, &Canvas);
          }
          Canvas.Flush_GameThread();
          ViewportClient->ProcessScreenShots(this);
      }
      
      5. void UGameViewportClient::Draw(FViewport* InViewport, FCanvas* SceneCanvas)
      {
          // 1.創建用于將世界場景渲染到視區的渲染目標的視圖族
          FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
              InViewport,
              MyWorld->Scene,
              EngineShowFlags)
              .SetRealtimeUpdate(true));
      
          // 2.計算所有玩家的視圖信息。
          for (FLocalPlayerIterator Iterator(GEngine, MyWorld); Iterator; ++Iterator)
          {
              ULocalPlayer* LocalPlayer = *Iterator;
              if (LocalPlayer)
              {
                  APlayerController* PlayerController = LocalPlayer->PlayerController;
      
                  const bool bEnableStereo = GEngine->IsStereoscopic3D(InViewport);
                  const int32 NumViews = bStereoRendering ? ((ViewFamily.IsMonoscopicFarFieldEnabled()) ? 3 : GEngine->StereoRenderingDevice->GetDesiredNumberOfViews(bStereoRendering)) : 1;
      
                  for (int32 i = 0; i < NumViews; ++i)
                  {
                      // 計算玩家的視圖信息。
                      FVector ViewLocation;
                      FRotator ViewRotation;
      
                      EStereoscopicPass PassType = bStereoRendering ? GEngine->StereoRenderingDevice->GetViewPassForIndex(bStereoRendering, i) : eSSP_FULL;
      
                      FSceneView* View = LocalPlayer->CalcSceneView(&ViewFamily, ViewLocation, ViewRotation, InViewport, &GameViewDrawer, PassType);
                  }
              }
          }
      
          // 3.繪制玩家視圖
          if (!bDisableWorldRendering && !bUIDisableWorldRendering && PlayerViewMap.Num() > 0 && FSlateApplication::Get().GetPlatformApplication()->IsAllowedToRender()) //-V560
          {
              GetRendererModule().BeginRenderingViewFamily(SceneCanvas,&ViewFamily);
          }
          else
          {
              // Make sure RHI resources get flushed if we're not using a renderer
              ENQUEUE_UNIQUE_RENDER_COMMAND( UGameViewportClient_FlushRHIResources,{
                  FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources);
              });
          }
      }
      
      5-1. FSceneView* ULocalPlayer::CalcSceneView( class FSceneViewFamily* ViewFamily,
          FVector& OutViewLocation,
          FRotator& OutViewRotation,
          FViewport* Viewport,
          class FViewElementDrawer* ViewDrawer,
          EStereoscopicPass StereoPass)
      {
          SCOPE_CYCLE_COUNTER(STAT_CalcSceneView);
      
          FSceneViewInitOptions ViewInitOptions;
      
          if (!CalcSceneViewInitOptions(ViewInitOptions, Viewport, ViewDrawer, StereoPass))
          {
              return nullptr;
          }
      
          // Get the viewpoint...technically doing this twice
          // but it makes GetProjectionData better
          FMinimalViewInfo ViewInfo;
          GetViewPoint(ViewInfo, StereoPass);
          OutViewLocation = ViewInfo.Location;
          OutViewRotation = ViewInfo.Rotation;
          ViewInitOptions.bUseFieldOfViewForLOD = ViewInfo.bUseFieldOfViewForLOD;
          ViewInitOptions.FOV = ViewInfo.FOV;
          ViewInitOptions.DesiredFOV = ViewInfo.DesiredFOV;
      
          // Fill out the rest of the view init options
          ViewInitOptions.ViewFamily = ViewFamily;
      }
      
      5-2. bool ULocalPlayer::CalcSceneViewInitOptions(
          struct FSceneViewInitOptions& ViewInitOptions,
          FViewport* Viewport,
          class FViewElementDrawer* ViewDrawer,
          EStereoscopicPass StereoPass)
      {
          // get the projection data
          if (GetProjectionData(Viewport, StereoPass, /*inout*/ ViewInitOptions) == false)
          {
              // Return NULL if this we didn't get back the info we needed
              return false;
          }
      }
      
      5-3. bool ULocalPlayer::GetProjectionData(FViewport* Viewport, EStereoscopicPass StereoPass, FSceneViewProjectionData& ProjectionData) const
      {
          ProjectionData.SetViewRectangle(UnconstrainedRectangle);
      
          // Get the viewpoint.
          FMinimalViewInfo ViewInfo;
          GetViewPoint(/*out*/ ViewInfo, StereoPass);
      
          // Create the view matrix
          ProjectionData.ViewOrigin = StereoViewLocation;
          ProjectionData.ViewRotationMatrix = FInverseRotationMatrix(ViewInfo.Rotation) * FMatrix(
          FPlane(0, 0, 1, 0),
          FPlane(1, 0, 0, 0),
          FPlane(0, 1, 0, 0),
          FPlane(0, 0, 0, 1));
      }

       


      四、渲染模塊繪制玩家視圖。

      //////////////////////////////////////////////////////////////////////////////////////////////
      /**
      *渲染器場景是渲染器模塊專用的。
      *通常這是UWorld的渲染器版本,但也可以創建FScene以在沒有UWorld的編輯器中預覽。
      *場景存儲獨立于任何視圖或幀的渲染器狀態,主要操作是添加和刪除基本體和燈光。
      */
      class FScene : public FSceneInterface
      {
      public:
      
          /** An optional world associated with the scene. */
          UWorld* World;
      
      }
      
      /**
      *用作場景渲染功能的范圍。
      *它在游戲線程中由 FSceneViewFamily::BeginRender 初始化,然后傳遞給呈現線程。
      *渲染線程調用 Render(),并在返回時刪除場景渲染器。
      */
      class FSceneRenderer
      {
      public:
          virtual void Render(FRHICommandListImmediate& RHICmdList) = 0;
          virtual void RenderHitProxies(FRHICommandListImmediate& RHICmdList) {}
      
          /** Creates a scene renderer based on the current feature level. */
          static FSceneRenderer* CreateSceneRenderer(const FSceneViewFamily* InViewFamily, FHitProxyConsumer* HitProxyConsumer);
      
      public:
          /** The views being rendered. */
          TArray<FViewInfo> Views;
      }
      
      /**
      * 實現簡單前向著色和相關功能的渲染器。
      */
      class FMobileSceneRenderer : public FSceneRenderer
      {
      public:
          /** 渲染視圖族。 */
          virtual void Render(FRHICommandListImmediate& RHICmdList) override;
      
          /**
          *初始化場景視圖。
          *檢查可見性,對半透明項進行排序等。
          */
          void InitViews(FRHICommandListImmediate& RHICmdList);
      }
      
      /**
      * 實現延遲著色管道和相關功能的場景渲染器。
      */
      class FDeferredShadingSceneRenderer : public FSceneRenderer
      {
          /** 渲染視圖族。 */
          virtual void Render(FRHICommandListImmediate& RHICmdList) override;
      
          /** 確定每個視圖可見的基元. */
          bool InitViews(FRHICommandListImmediate& RHICmdList, struct FILCUpdatePrimTaskData& ILCTaskData, FGraphEventArray& SortEvents, FGraphEventArray& UpdateViewCustomDataEvents);
      }
      
      /** 具有場景渲染器使用的附加狀態的FSceneView. */
      class FViewInfo : public FSceneView
      {
      }
      //////////////////////////////////////////////////////////////////////////////////////////////
      // 渲染模塊繪制玩家視圖流程:
      1. void FRendererModule::BeginRenderingViewFamily(FCanvas* Canvas, FSceneViewFamily* ViewFamily)
      {
          UWorld* World = nullptr;
      
          FScene* const Scene = ViewFamily->Scene->GetRenderScene();
          if (Scene)
          {
              World = Scene->GetWorld();
              if (World)
              {
                  //確保所有渲染代理在啟動BeginEnderView族之前都是最新的
                  World->SendAllEndOfFrameUpdates();
              }
          }
      
          if (Scene)
          {
              // 構建場景渲染器。這會將視圖族屬性復制到自己的結構中。
              FSceneRenderer* SceneRenderer = FSceneRenderer::CreateSceneRenderer(ViewFamily, Canvas->GetHitProxyConsumer());
      
              RenderViewFamily_RenderThread(RHICmdList, SceneRenderer);
          }
      }
      
      // 將所有渲染更新發送到渲染線程。
      2. void UWorld::SendAllEndOfFrameUpdates()
      {
      }
      
      // 基于當前功能級別創建場景渲染器
      3. FSceneRenderer* FSceneRenderer::CreateSceneRenderer(const FSceneViewFamily* InViewFamily, FHitProxyConsumer* HitProxyConsumer)
      {
          EShadingPath ShadingPath = InViewFamily->Scene->GetShadingPath();
          FSceneRenderer* SceneRenderer = nullptr;
      
          if (ShadingPath == EShadingPath::Deferred)
          {
              SceneRenderer = new FDeferredShadingSceneRenderer(InViewFamily, HitProxyConsumer);
          }
          else
          {
              check(ShadingPath == EShadingPath::Mobile);
              SceneRenderer = new FMobileSceneRenderer(InViewFamily, HitProxyConsumer);
          }
      
          return SceneRenderer;
      }
      
      /**
      * 輔助函數在渲染線程中執行實際工作。
      */
      4. static void RenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer)
      {
          if(SceneRenderer->ViewFamily.EngineShowFlags.HitProxies)
          {
              // 渲染場景的命中代理。
              SceneRenderer->RenderHitProxies(RHICmdList);
          }
          else
          {
              // 渲染場景。
              SceneRenderer->Render(RHICmdList);
          }
      }
      
      /**
      * 渲染視圖族。
      */
      // 移動端渲染器
      5. void FMobileSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
      {
          // 找出可見的原始組件。
          InitViews(RHICmdList);
      
          RHICmdList.SetCurrentStat(GET_STATID(STAT_CLMM_BasePass));
          RenderMobileBasePass(RHICmdList, ViewList);
      
          RHICmdList.SetCurrentStat(GET_STATID(STAT_CLMM_Occlusion));
          // Issue occlusion queries
          RenderOcclusion(RHICmdList);
      
          RHICmdList.SetCurrentStat(GET_STATID(STAT_CLMM_SceneEnd));
          RenderFinish(RHICmdList);
      }
      // 延遲渲染器
      void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
      {
          bool bDoInitViewAftersPrepass = InitViews(RHICmdList, ILCTaskData, SortEvents, UpdateViewCustomDataEvents);
      
          RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_BasePass));
          RenderBasePass(RHICmdList, BasePassDepthStencilAccess, ForwardScreenSpaceShadowMask.GetReference());
          RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterBasePass));
          ServiceLocalQueue();
      
          {
              SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderFinish);
              RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_RenderFinish));
              RenderFinish(RHICmdList);
              RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterFrame));
          }
          ServiceLocalQueue();
      }
      
      /**
      * Initialize scene's views.
      * Check visibility, sort translucent items, etc.
      */
      6. void FMobileSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList)
      {
          RHICmdList.SetCurrentStat(GET_STATID(STAT_CLMM_InitVIews));
      
          SCOPED_DRAW_EVENT(RHICmdList, InitViews);
      
          SCOPE_CYCLE_COUNTER(STAT_InitViewsTime);
      
          FILCUpdatePrimTaskData ILCTaskData;
          PreVisibilityFrameSetup(RHICmdList);
          ComputeViewVisibility(RHICmdList);
          PostVisibilityFrameSetup(ILCTaskData);
      
          const bool bDynamicShadows = ViewFamily.EngineShowFlags.DynamicShadows;
      
          if (bDynamicShadows && !IsSimpleForwardShadingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel)))
          {
              // Setup dynamic shadows.
              InitDynamicShadows(RHICmdList);
          }
      
          // if we kicked off ILC update via task, wait and finalize.
          if (ILCTaskData.TaskRef.IsValid())
          {
              Scene->IndirectLightingCache.FinalizeCacheUpdates(Scene, *this, ILCTaskData);
          }
      
          // initialize per-view uniform buffer. Pass in shadow info as necessary.
          for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
          {
              // Initialize the view's RHI resources.
              Views[ViewIndex].InitRHIResources();
      
              // Create the directional light uniform buffers
              CreateDirectionalLightUniformBuffers(Views[ViewIndex]);
          }
      
          // Now that the indirect lighting cache is updated, we can update the primitive precomputed lighting buffers.
          UpdatePrimitivePrecomputedLightingBuffers();
      
          UpdatePostProcessUsageFlags();
      
          PostInitViewCustomData();
      
          OnStartFrame(RHICmdList);
      }
      
      7. void FSceneRenderer::OnStartFrame(FRHICommandListImmediate& RHICmdList)
      {
          for(FViewInfo& View : Views)
          {
              if(View.ViewState)
              {
                  View.ViewState->OnStartFrame(View, ViewFamily);
              }
          }
      }
      //////////////////////////////////////////////////////////////////////////////////////////////
      // StaticMesh的繪制流程
      
      // 延遲渲染器
      1. void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
      {
          RenderBasePass(RHICmdList, BasePassDepthStencilAccess, ForwardScreenSpaceShadowMask.GetReference());
      }
      
      
      /**
      * 渲染場景的基礎通道
      */
      2. bool FDeferredShadingSceneRenderer::RenderBasePass(FRHICommandListImmediate& RHICmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, IPooledRenderTarget* ForwardScreenSpaceShadowMask)
      {
      }
      
      template<typename DrawingPolicyType>
      template<InstancedStereoPolicy InstancedStereo>
      3. bool TStaticMeshDrawList<DrawingPolicyType>::DrawVisibleInner(
          FRHICommandList& RHICmdList,
          const FViewInfo& View,
          const typename DrawingPolicyType::ContextDataType PolicyContext,
          FDrawingPolicyRenderState& DrawRenderState,
          const TBitArray<SceneRenderingBitArrayAllocator>* const StaticMeshVisibilityMap,
          const TArray<uint64, SceneRenderingAllocator>* const BatchVisibilityArray,
          const StereoPair* const StereoView,
          int32 FirstPolicy, int32 LastPolicy,
          bool bUpdateCounts
      )
      {
          Count += DrawElement<InstancedStereoPolicy::Disabled>(RHICmdList, View, PolicyContext, DrawRenderState, Element, BatchElementMask,
      }
      
      template<typename DrawingPolicyType>
      template<InstancedStereoPolicy InstancedStereo>
      4. int32 TStaticMeshDrawList<DrawingPolicyType>::DrawElement(
          FRHICommandList& RHICmdList,
          const FViewInfo& View,
          const typename DrawingPolicyType::ContextDataType PolicyContext,
          FDrawingPolicyRenderState& DrawRenderState,
          const FElement& Element,
          uint64 BatchElementMask,
          FDrawingPolicyLink* DrawingPolicyLink,
          bool& bDrawnShared
      )
      {
          DrawingPolicyLink->DrawingPolicy.DrawMesh(RHICmdList, View, *Element.Mesh, BatchElementIndex, true);
      }
      
      5. void FMeshDrawingPolicy::DrawMesh(FRHICommandList& RHICmdList, const FSceneView& View, const FMeshBatch& Mesh, int32 BatchElementIndex, const bool bIsInstancedStereo) const
      {
          RHICmdList.DrawIndexedPrimitive(
              BatchElement.IndexBuffer->IndexBufferRHI,
              Mesh.Type,
              BatchElement.BaseVertexIndex,
              0,
              BatchElement.MaxVertexIndex - BatchElement.MinVertexIndex + 1,
              BatchElement.FirstIndex,
              BatchElement.NumPrimitives,
              InstanceCount * GetInstanceFactor()
          );
      }
      
      6. void FD3D11DynamicRHI::RHIDrawIndexedPrimitive(FIndexBufferRHIParamRef IndexBufferRHI,uint32 PrimitiveType,int32 BaseVertexIndex,uint32 FirstInstance,uint32 NumVertices,uint32 StartIndex,uint32 NumPrimitives,uint32 NumInstances)
      {
          FD3D11IndexBuffer* IndexBuffer = ResourceCast(IndexBufferRHI);
      
          // called should make sure the input is valid, this avoid hidden bugs
          ensure(NumPrimitives > 0);
      
          RHI_DRAW_CALL_STATS(PrimitiveType,NumInstances*NumPrimitives);
      
          GPUProfilingData.RegisterGPUWork(NumPrimitives * NumInstances, NumVertices * NumInstances);
      
          CommitGraphicsResourceTables();
          CommitNonComputeShaderConstants();
      
          // determine 16bit vs 32bit indices
          uint32 SizeFormat = sizeof(DXGI_FORMAT);
          const DXGI_FORMAT Format = (IndexBuffer->GetStride() == sizeof(uint16) ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT);
      
          uint32 IndexCount = GetVertexCountForPrimitiveCount(NumPrimitives,PrimitiveType);
      
          // Verify that we are not trying to read outside the index buffer range
          // test is an optimized version of: StartIndex + IndexCount <= IndexBuffer->GetSize() / IndexBuffer->GetStride()
          checkf((StartIndex + IndexCount) * IndexBuffer->GetStride() <= IndexBuffer->GetSize(),
          TEXT("Start %u, Count %u, Type %u, Buffer Size %u, Buffer stride %u"), StartIndex, IndexCount, PrimitiveType, IndexBuffer->GetSize(), IndexBuffer->GetStride());
      
          StateCache.SetIndexBuffer(IndexBuffer->Resource, Format, 0);
          VerifyPrimitiveType(PSOPrimitiveType, PrimitiveType);
          StateCache.SetPrimitiveTopology(GetD3D11PrimitiveType(PrimitiveType,bUsingTessellation));
      
          if (NumInstances > 1 || FirstInstance != 0)
          {
              const uint64 TotalIndexCount = (uint64)NumInstances * (uint64)IndexCount + (uint64)StartIndex;
              checkf(TotalIndexCount <= (uint64)0xFFFFFFFF, TEXT("Instanced Index Draw exceeds maximum d3d11 limit: Total: %llu, NumInstances: %llu, IndexCount: %llu, StartIndex: %llu, FirstInstance: %llu"), TotalIndexCount, NumInstances, IndexCount, StartIndex, FirstInstance);
              Direct3DDeviceIMContext->DrawIndexedInstanced(IndexCount, NumInstances, StartIndex, BaseVertexIndex, FirstInstance);
          }
          else
          {
              Direct3DDeviceIMContext->DrawIndexed(IndexCount,StartIndex,BaseVertexIndex);
          }
      }

       

      //////////////////////////////////////////////////////////////////////////////////////////////
      // 通過宏來創建渲染任務
      ENQUEUE_UNIQUE_RENDER_COMMAND
      
      // 通過模板函數來創建渲染任務
      template<typename TSTR, typename LAMBDA>
      FORCEINLINE_DEBUGGABLE void EnqueueUniqueRenderCommand(LAMBDA&& Lambda)
      {
          typedef TEnqueueUniqueRenderCommandType<TSTR, LAMBDA> EURCType;
      
          #if 0 // UE_SERVER && UE_BUILD_DEBUG
              UE_LOG(LogRHI, Warning, TEXT("Render command '%s' is being executed on a dedicated server."), TSTR::TStr())
          #endif
          // always use a new task for devices that have GUseThreadedRendering=false
          // even when the call is from the rendering thread
          if (GUseThreadedRendering && IsInRenderingThread())
          {
              FRHICommandListImmediate& RHICmdList = GetImmediateCommandList_ForRenderCommand();
              Lambda(RHICmdList);
          }
          else
          {
              if (ShouldExecuteOnRenderThread())
              {
                  CheckNotBlockedOnRenderThread();
                  TGraphTask<EURCType>::CreateTask().ConstructAndDispatchWhenReady(Forward<LAMBDA>(Lambda));
              }
              else
              {
                  EURCType TempCommand(Forward<LAMBDA>(Lambda));
                  FScopeCycleCounter EURCMacro_Scope(TempCommand.GetStatId());
                  TempCommand.DoTask(ENamedThreads::GameThread, FGraphEventRef());
              }
          }
      }

       參考:

      1、渲染一個正方體的堆棧信息

      2、圖表

      主站蜘蛛池模板: 在线高清免费不卡全码| 亚洲人妻精品一区二区| 中文乱码字幕在线中文乱码| 人妻少妇精品专区性色av| 日本边添边摸边做边爱喷水| 日韩精品中文字幕亚洲| 国产精品夜夜春夜夜爽久久小| 国产精品一区 在线播放| 少妇人妻偷人精品免费| 女人被狂c躁到高潮视频| 国产揄拍国产精品| 亚洲欧美日产综合在线网| 人妻丝袜AV中文系列先锋影音| 国产免费午夜福利片在线| аⅴ天堂中文在线网| 日本大片在线看黄a∨免费| 国产av永久无码天堂影院| 亚洲sm另类一区二区三区| 中文字幕av日韩有码| 诸暨市| 元码人妻精品一区二区三区9| 在线观看AV永久免费| 中国女人熟毛茸茸A毛片| 洛阳市| 特黄做受又粗又大又硬老头| 成人免费无遮挡在线播放| 无码一区中文字幕| 国产精品一二三中文字幕| 欧美人禽杂交狂配| 免费拍拍拍网站| 欧美熟妇乱子伦XX视频| 亚洲码国产精品高潮在线| 国产一级片内射在线视频| 国产乱人伦真实精品视频| 男人扒女人添高潮视频| 亚洲成a人v欧美综合天堂下载| 日日麻批免费40分钟无码| 永久免费无码成人网站| 午夜福利在线观看6080| 无码av永久免费专区麻豆| 亚洲男人在线天堂|