Filament源碼分析 - FrameGraph / RenderGraph

放一下類圖。node

簡單介紹一下相關類型:數組

  • FrameGraphHandle:只有一個uint16_t的標識,初始化爲一個無效值。
  • FrameGraphId:一個模板類,繼承自FrameGraphHandle,沒有自定義的屬性或者方法。
  • FrameGraphRenderTarget: 一個命名空間,裏面定義了Attachments和Descriptor兩個結構體。
  1. Attachments,主要定義了AttachmentInfo這個內部結構,AttachmentInfo有兩個屬性:FrameGraphId<FrameGraphTexture>類型的handle(僅僅是個handle,對應的是ResourceNode,並非真正的紋理資源)和一個mLevel(紋理的mipmap level)。一個Attachments包含了兩個AttachmentInfo,這裏寫死了。

    

          2. Descriptor:包含三個屬性:Attachments, Viewport 和 samples緩存

  • FrameGraphTexture: 定義了一個內部結構Descriptor,實現了方法create/destroy,持有真正的gpu資源。其建立和銷燬均經過調用FrameGraph類的ResourceAllocator相應方法實現。
  • VirtualResource:資源類的祖先。定義了虛方法create和destroy,有兩個PassNode類型的指針,指向第一個和最後一個ref這個資源的pass,在FrameGraph的方法compile內計算賦值的。
  • ResourceEntryBase:繼承自VirtualResource,id,name變量沒啥用,imported標記資源是否FrameGraph外部導入,uint8_t型version變量,還有一個引用計數,fg.compile內更新爲:全部相關ResourceNode的readerCount之和。
  • ResourceEntry<T>,一個模板類,繼承自ResourceEntryBase。包含T類型的resource屬性和T::Descriptor類型的descriptor屬性。實現了VirtualResource定義的兩個虛接口,當!imported時會調用resource.相應方法。一個經常使用的實例化爲T=FrameGraphTexture。ResourceEntry有兩個構造,其中一個包含一個T類型的引用,這時會將import置爲true,意思是這個資源是外部引入的。這時候咱們注意到:ResourceEntryBase/ResourceEntry都是不能經過handle來查找訪問的。這時候須要一個類ResourceNode。
  • ResourceNode:資源節點類。構造時須要傳入一個ResourceEntryBase指針和一個uint8_t的version,ResourceEntryBase指向其對應的資源(好比一張紋理),version初始化爲ResourceEntryBase的version。PassNode* writer指針指向寫入這個資源的pass,只有一個?引用計數readerCount,還有一個renderTargetIndex,是fg中rt數組的索引,用來獲取rt的信息?
  • RenderTargetResource:繼承自VirtualResource,構造時須要傳入FrameGraphRenderTarget::Descriptor的描述,是否imported,backend::TargetBufferFlags,寬高,紋理格式。主要包含一個FrameGraphPassResources::RenderTargetInfo類型的屬性,其只有真正的硬件資源和backend::RenderPassParams params(包含viewport,discardstart,end等信息)。也是資源類,因此須要實現create/destroy兩個接口,具體也是根據Descriptor調用FrameGraph類的ResourceAllocator相應方法實現。
  • RenderTarget:構造時須要傳入FrameGraphRenderTarget::Descriptor,fg中數組索引,及name。包含屬性:backend::TargetBufferFlags userClearFlags,backend::RenderPassFlags targetFlags及RenderTargetResource* cache等。其包含一個方法:void resolve(FrameGraph& fg) noexcept,負責初始化RenderTargetResource* cache指針,具體實現爲:首先根據Descriptor去fg的緩存中找(FrameGraph會緩存一個RenderTargetResource的列表),找到直接賦值而後執行一個cache->targetInfo.params.flags.clear |= userClearFlags;操做。不然從新建立一個新的。
  • FrameGraphPassResources:雖然也叫Resource但非繼承自VirtualResource。構造時須要傳入一個FrameGraph的引用和一個PassNode的引用,將其緩存下來。提供了幾個get方法來從fg裏面獲取資源或者描述等信息,裏面定義告終構RenderTargetInfo:

    

  • FrameGraphPassExecutor:只定義了一個接口virtual void execute(FrameGraphPassResources const& resources, backend::DriverApi& driver) noexcept = 0;
  • FrameGraphPass<typename Data, typename Execute>:一個模板類,繼承自FrameGraphPassExecutor,包含兩個變量:Execute mExecute和Data mData。構造時須要傳入一個Execute&& execute。實現了父類的execute方法,只有一行代碼:mExecute(resources, mData, driver); 全部pass的具體操做都是經過這個Execute傳入執行的。
  • PassNode:構造時須要傳入FrameGraph的引用,name,id, 及一個FrameGraphPassExecutor的指針。表明一個pass。

  主要屬性:ide

  1. FrameGraph::UniquePtr<FrameGraphPassExecutor> base; // type eraser for calling execute()。
  2. 該pass reads/writes的資源handle列表。
  3. renderTargets列表。
  4. 該pass須要devirtualize/destroy的VirtualResource*列表。
  5. refCount // count resources that have a reference to us
  6. hasSideEffect // whether this pass has side effects

  主要方法:ui

  1. FrameGraphHandle read(FrameGraph& fg, FrameGraphHandle const& handle, bool isRenderTarget = false);將資源handle添加到reads列表中,保證不重複,且會確保相應資源描述爲backend::TextureUsage::SAMPLEABLE
  2. FrameGraphHandle write(FrameGraph& fg, const FrameGraphHandle& handle);主要操做爲:將資源的version加1,以前/傳入的handle就無效了。若是資源是imported的,則將hasSideEffect置true。建立一個新的handle返回。
  3. void declareRenderTarget(fg::RenderTarget& renderTarrget);添加一個renderTarrget的id到renderTargets列表中。
  • ResourceAllocator: 提供了RT、Texture的建立和銷燬實現。關於Texture的建立和銷燬,維護了兩個列表:在用的Texture和cache的texture。銷燬時能夠不執行真正的紋理銷燬而是將其加入到cache列表(從在用列表中移除)。這樣下次若是須要建立新的紋理時先去cache列表中找,若是找到就不用建立新的紋理了,將其添加到在用列表中。並提供了一個gc實現來釋放cache的紋理資源。
  • FrameGraph::Builder:構造時須要傳入FrameGraph和PassNode的引用,提供一些資源的建立和銷燬操做轉發到緩存的FrameGraph/PassNode引用對象上。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------this

以上是FrameGraph相關的基礎類,關於FrameGraph類:3d

  • 構造時須要傳入一個ResourceAllocator
  • 主要屬性:PassNode列表,ResourceNode列表,RenderTarget列表。ResourceEntryBase列表、RenderTargetResource列表(這兩個列表存放真正的資源)。Alias資源重命名列表。
  • 模板方法

    template <typename Data, typename Setup, typename Execute>
    FrameGraphPass<Data, Execute>& addPass(const char* name, Setup setup, Execute&& execute)指針

   添加一個pass到pass列表中,並執行指定的Setup操做對象

  • void present(FrameGraphHandle input)方法爲‘input’添加一個引用,防止被cull掉。
  • bool isValid(FrameGraphHandle r)。判斷一個handle是否有效。主要判斷其node.version和指向資源的version是否相同。A resource handle becomes invalid after it's used to declare a resource write
  • importResource方法:引入一個外部RT。主要操做:建立一個紋理資源handle/node(並未指向真正的硬件資源)。建立一個RenderTargetResource,填充相應信息,添加到cache列表中,等待resolve。
  • FrameGraphId<T> import方法:引入一個現有resource。主要操做:建立一個imported標記的ResourceEntryBase指針(緩存到ResourceEntryBase中),而後建立一個ResourceNode。返回handle。
  • moveResource(FrameGraphHandle from, FrameGraphHandle to)方法:all handles referring to the resource 'to' are redirected to the resource 'from'。 handle 'from' 失效了,返回一個新的handle。
  • compile方法:
  1. 處理mAliases:將全部指向to.resource的node的資源指向from.resource。若是某個rt包含指向from節點的resource的color attachment,且這個resource是imported,那麼將這個rt的全部非color attachments置無效。處理全部pass的reads:若是是from,那麼改爲to。處理全部pass的writes:erase掉全部from。
  2. 更新pass和資源的refCount,並更新每一個資源的writer爲相應pass節點:pass的置爲writes和hasSideEffect之和。resource爲read該資源的pass數目。
  3. cull passes and resources:若是資源的readerCount爲0,入棧。遍歷棧中元素:若是writer不爲空,那麼writer的引用減一,若是writer的引用變0,將其全部的reads計數減1。最後根據node的計數更新resource的計數(由於多個node可能指向相同的resource)。
  4. resolve全部pass的全部rt。
  5. 對於全部資源(rt和紋理等),計算第一次及最後一次訪問其的pass節點。
  6. 遍歷全部資源,若是引用計數不爲0的話,將其添加到第一次及最後一次訪問其的pass節點中的devirtualize/destroy列表中。
  • execute方法:依序執行全部的pass:建立資源,執行,釋放資源。
相關文章
相關標籤/搜索