RenderGraph.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <LyShine/IRenderGraph.h>
  10. #include <LyShine/UiRenderFormats.h>
  11. #include <AzCore/Memory/PoolAllocator.h>
  12. #include <AzCore/std/containers/stack.h>
  13. #include <AzCore/std/containers/set.h>
  14. #include <AzCore/Math/Color.h>
  15. #include <Atom/RPI.Public/Image/AttachmentImage.h>
  16. #include <Atom/RPI.Reflect/Image/Image.h>
  17. #include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
  18. #include <AtomCore/Instance/Instance.h>
  19. #include "UiRenderer.h"
  20. #include "LyShinePass.h"
  21. #ifndef _RELEASE
  22. #include "LyShineDebug.h"
  23. #endif
  24. namespace LyShine
  25. {
  26. enum RenderNodeType
  27. {
  28. PrimitiveList,
  29. Mask,
  30. RenderTarget
  31. };
  32. enum class AlphaMaskType
  33. {
  34. None,
  35. ModulateAlpha,
  36. ModulateAlphaAndColor
  37. };
  38. // Abstract base class for nodes in the render graph
  39. class RenderNode
  40. {
  41. public: // functions
  42. RenderNode(RenderNodeType type) : m_type(type) {}
  43. virtual ~RenderNode() {};
  44. virtual void Render(UiRenderer* uiRenderer
  45. , const AZ::Matrix4x4& modelViewProjMat
  46. , AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) = 0;
  47. RenderNodeType GetType() const { return m_type; }
  48. #ifndef _RELEASE
  49. // A debug-only function useful for debugging
  50. virtual void ValidateNode() = 0;
  51. #endif
  52. private: // data
  53. RenderNodeType m_type;
  54. };
  55. //! This custom allocator class is used to provide runtime type information
  56. //! so we can differentiate this allocator from other PoolAllocators
  57. class LyShinePoolAllocator final
  58. : public AZ::PoolAllocator
  59. {
  60. public:
  61. AZ_RTTI(LyShinePoolAllocator, "{0FFA2FE4-498A-4FF6-A58A-F49F0E8575EE}", AZ::PoolAllocator);
  62. };
  63. // As we build the render graph we allocate a render node for each change in render state
  64. class PrimitiveListRenderNode : public RenderNode
  65. {
  66. public: // functions
  67. // We use a pool allocator to keep these allocations fast.
  68. AZ_CLASS_ALLOCATOR(PrimitiveListRenderNode, LyShinePoolAllocator);
  69. PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, const AZ::RHI::TargetBlendState& blendModeState);
  70. PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, const AZ::Data::Instance<AZ::RPI::Image>& maskTexture,
  71. bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, const AZ::RHI::TargetBlendState& blendModeState);
  72. ~PrimitiveListRenderNode() override;
  73. void Render(UiRenderer* uiRenderer
  74. , const AZ::Matrix4x4& modelViewProjMat
  75. , AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) override;
  76. void AddPrimitive(LyShine::UiPrimitive* primitive);
  77. LyShine::UiPrimitiveList& GetPrimitives() const;
  78. int GetOrAddTexture(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode);
  79. int GetNumTextures() const { return m_numTextures; }
  80. const AZ::Data::Instance<AZ::RPI::Image> GetTexture(int texIndex) const { return m_textures[texIndex].m_texture; }
  81. bool GetTextureIsClampMode(int texIndex) const { return m_textures[texIndex].m_isClampTextureMode; }
  82. bool GetIsTextureSRGB() const { return m_isTextureSRGB; }
  83. AZ::RHI::TargetBlendState GetBlendModeState() const { return m_blendModeState; }
  84. bool GetIsPremultiplyAlpha() const { return m_preMultiplyAlpha; }
  85. AlphaMaskType GetAlphaMaskType() const { return m_alphaMaskType; }
  86. bool HasSpaceToAddPrimitive(LyShine::UiPrimitive* primitive) const;
  87. // Search to see if this texture is already used by this texture unit, returns -1 if not used
  88. int FindTexture(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode) const;
  89. #ifndef _RELEASE
  90. // A debug-only function useful for debugging
  91. void ValidateNode() override;
  92. #endif
  93. public: // data
  94. static const int MaxTextures = 16;
  95. private: // types
  96. struct TextureUsage
  97. {
  98. AZ::Data::Instance<AZ::RPI::Image> m_texture;
  99. bool m_isClampTextureMode;
  100. };
  101. private: // data
  102. TextureUsage m_textures[MaxTextures];
  103. int m_numTextures;
  104. bool m_isTextureSRGB;
  105. bool m_preMultiplyAlpha;
  106. AlphaMaskType m_alphaMaskType;
  107. AZ::RHI::TargetBlendState m_blendModeState;
  108. int m_totalNumVertices;
  109. int m_totalNumIndices;
  110. LyShine::UiPrimitiveList m_primitives;
  111. };
  112. // A mask render node handles using one set of render nodes to mask another set of render nodes
  113. class MaskRenderNode : public RenderNode
  114. {
  115. public: // functions
  116. // We use a pool allocator to keep these allocations fast.
  117. AZ_CLASS_ALLOCATOR(MaskRenderNode, LyShinePoolAllocator);
  118. MaskRenderNode(MaskRenderNode* parentMask, bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront);
  119. ~MaskRenderNode() override;
  120. void Render(UiRenderer* uiRenderer
  121. , const AZ::Matrix4x4& modelViewProjMat
  122. , AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) override;
  123. AZStd::vector<RenderNode*>& GetMaskRenderNodeList() { return m_maskRenderNodes; }
  124. const AZStd::vector<RenderNode*>& GetMaskRenderNodeList() const { return m_maskRenderNodes; }
  125. AZStd::vector<RenderNode*>& GetContentRenderNodeList() { return m_contentRenderNodes; }
  126. const AZStd::vector<RenderNode*>& GetContentRenderNodeList() const { return m_contentRenderNodes; }
  127. MaskRenderNode* GetParentMask() { return m_parentMask; }
  128. //! if the mask has no content elements and is not drawing the mask primitives then there is no need to add a render node
  129. bool IsMaskRedundant();
  130. bool GetIsMaskingEnabled() const { return m_isMaskingEnabled; }
  131. bool GetUseAlphaTest() const { return m_useAlphaTest; }
  132. bool GetDrawBehind() const { return m_drawBehind; }
  133. bool GetDrawInFront() const { return m_drawInFront; }
  134. #ifndef _RELEASE
  135. // A debug-only function useful for debugging
  136. void ValidateNode() override;
  137. #endif
  138. private: // functions
  139. void SetupBeforeRenderingMask(UiRenderer* uiRenderer,
  140. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw,
  141. bool firstPass, UiRenderer::BaseState priorBaseState);
  142. void SetupAfterRenderingMask(UiRenderer* uiRenderer,
  143. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw,
  144. bool firstPass, UiRenderer::BaseState priorBaseState);
  145. private: // data
  146. AZStd::vector<RenderNode*> m_maskRenderNodes; //!< The render nodes used to render the mask shape
  147. AZStd::vector<RenderNode*> m_contentRenderNodes; //!< The render nodes that are masked by this mask
  148. MaskRenderNode* m_parentMask = nullptr; //! Used while building the render graph.
  149. // flags that control the render behavior of the mask
  150. bool m_isMaskingEnabled = true;
  151. bool m_useAlphaTest = false;
  152. bool m_drawBehind = false;
  153. bool m_drawInFront = false;
  154. };
  155. // A render target render node renders its child render nodes to a given render target
  156. class RenderTargetRenderNode : public RenderNode
  157. {
  158. public: // functions
  159. // We use a pool allocator to keep these allocations fast.
  160. AZ_CLASS_ALLOCATOR(RenderTargetRenderNode, LyShinePoolAllocator);
  161. RenderTargetRenderNode(RenderTargetRenderNode* parentRenderTarget,
  162. AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage,
  163. const AZ::Vector2& viewportTopLeft,
  164. const AZ::Vector2& viewportSize,
  165. const AZ::Color& clearColor,
  166. int nestLevel);
  167. ~RenderTargetRenderNode() override;
  168. void Render(UiRenderer* uiRenderer
  169. , const AZ::Matrix4x4& modelViewProjMat
  170. , AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw) override;
  171. AZStd::vector<RenderNode*>& GetChildRenderNodeList() { return m_childRenderNodes; }
  172. const AZStd::vector<RenderNode*>& GetChildRenderNodeList() const { return m_childRenderNodes; }
  173. RenderTargetRenderNode* GetParentRenderTarget() { return m_parentRenderTarget; }
  174. float GetViewportX() const { return m_viewportX; }
  175. float GetViewportY() const { return m_viewportY; }
  176. float GetViewportWidth() const { return m_viewportWidth; }
  177. float GetViewportHeight() const { return m_viewportHeight; }
  178. AZ::Color GetClearColor() const { return m_clearColor; }
  179. const char* GetRenderTargetName() const;
  180. int GetNestLevel() const;
  181. const AZ::Data::Instance<AZ::RPI::AttachmentImage> GetRenderTarget() const;
  182. #ifndef _RELEASE
  183. // A debug-only function useful for debugging
  184. void ValidateNode() override;
  185. #endif
  186. //! Used to sort a list of RenderTargetNodes for render order
  187. static bool CompareNestLevelForSort(RenderTargetRenderNode* a, RenderTargetRenderNode* b);
  188. private: // functions
  189. private: // data
  190. AZStd::vector<RenderNode*> m_childRenderNodes; //!< The render nodes to render to the render target
  191. RenderTargetRenderNode* m_parentRenderTarget = nullptr; //! Used while building the render graph.
  192. AZ::Data::Instance<AZ::RPI::AttachmentImage> m_attachmentImage;
  193. // Each render target requires a unique dynamic draw context to draw to the raster pass associated with the target
  194. AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> m_dynamicDraw;
  195. float m_viewportX = 0;
  196. float m_viewportY = 0;
  197. float m_viewportWidth = 0;
  198. float m_viewportHeight = 0;
  199. AZ::Matrix4x4 m_modelViewProjMat;
  200. AZ::Color m_clearColor;
  201. int m_nestLevel = 0;
  202. };
  203. ////////////////////////////////////////////////////////////////////////////////////////////////////
  204. // The RenderGraph is owned by the canvas component
  205. class RenderGraph : public IRenderGraph
  206. {
  207. public:
  208. RenderGraph();
  209. ~RenderGraph() override;
  210. //! Free up all the memory and clear the lists
  211. void ResetGraph();
  212. // IRenderGraph
  213. void BeginMask(bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront) override;
  214. void StartChildrenForMask() override;
  215. void EndMask() override;
  216. void BeginRenderToTexture(AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage,
  217. const AZ::Vector2& viewportTopLeft,
  218. const AZ::Vector2& viewportSize,
  219. const AZ::Color& clearColor) override;
  220. void EndRenderToTexture() override;
  221. LyShine::UiPrimitive* GetDynamicQuadPrimitive(const AZ::Vector2* positions, uint32 packedColor) override;
  222. bool IsRenderingToMask() const override;
  223. void SetIsRenderingToMask(bool isRenderingToMask) override;
  224. void PushAlphaFade(float alphaFadeValue) override;
  225. void PushOverrideAlphaFade(float alphaFadeValue) override;
  226. void PopAlphaFade() override;
  227. float GetAlphaFade() const override;
  228. void AddPrimitive(LyShine::UiPrimitive* primitive, const AZ::Data::Instance<AZ::RPI::Image>& texture,
  229. bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode) override;
  230. // ~IRenderGraph
  231. //! Add an indexed triangle list primitive to the render graph which will use maskTexture as an alpha (gradient) mask
  232. void AddAlphaMaskPrimitive(LyShine::UiPrimitive* primitive,
  233. AZ::Data::Instance<AZ::RPI::AttachmentImage> contentAttachmentImage,
  234. AZ::Data::Instance<AZ::RPI::AttachmentImage> maskAttachmentImage,
  235. bool isClampTextureMode,
  236. bool isTextureSRGB,
  237. bool isTexturePremultipliedAlpha,
  238. BlendMode blendMode) override;
  239. //! Render the display graph
  240. void Render(UiRenderer* uiRenderer, const AZ::Vector2& viewportSize);
  241. //! Set the dirty flag - this also resets the graph
  242. void SetDirtyFlag(bool isDirty);
  243. //! Get the dirty flag
  244. bool GetDirtyFlag();
  245. //! End the building of the graph
  246. void FinalizeGraph();
  247. //! Test whether the render graph contains any render nodes
  248. bool IsEmpty();
  249. void GetRenderTargetsAndDependencies(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies);
  250. #ifndef _RELEASE
  251. // A debug-only function useful for debugging, not called but calls can be added during debugging
  252. void ValidateGraph();
  253. void GetDebugInfoRenderGraph(LyShineDebug::DebugInfoRenderGraph& info) const;
  254. void GetDebugInfoRenderNodeList(
  255. const AZStd::vector<RenderNode*>& renderNodeList,
  256. LyShineDebug::DebugInfoRenderGraph& info,
  257. AZStd::set<AZ::Data::Instance<AZ::RPI::Image>>& uniqueTextures) const;
  258. void DebugReportDrawCalls(AZ::IO::HandleType fileHandle, LyShineDebug::DebugInfoDrawCallReport& reportInfo, void* context) const;
  259. void DebugReportDrawCallsRenderNodeList(const AZStd::vector<RenderNode*>& renderNodeList, AZ::IO::HandleType fileHandle,
  260. LyShineDebug::DebugInfoDrawCallReport& reportInfo, void* context, const AZStd::string& indent) const;
  261. #endif
  262. protected: // types
  263. struct DynamicQuad
  264. {
  265. LyShine::UiPrimitiveVertex m_quadVerts[4];
  266. LyShine::UiPrimitive m_primitive;
  267. };
  268. protected: // member functions
  269. //! Given a blend mode and whether the shader will be outputing premultiplied alpha, return state flags
  270. AZ::RHI::TargetBlendState GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
  271. void SetRttPassesEnabled(UiRenderer* uiRenderer, bool enabled);
  272. protected: // data
  273. AZStd::vector<RenderNode*> m_renderNodes;
  274. AZStd::vector<DynamicQuad*> m_dynamicQuads; // used for drawing quads not cached in components
  275. MaskRenderNode* m_currentMask = nullptr;
  276. RenderTargetRenderNode* m_currentRenderTarget = nullptr;
  277. AZStd::stack<AZStd::vector<RenderNode*>*> m_renderNodeListStack;
  278. bool m_isDirty = true;
  279. int m_renderToRenderTargetCount = 0;
  280. bool m_isRenderingToMask = false;
  281. AZStd::stack<float> m_alphaFadeStack;
  282. AZStd::vector<RenderTargetRenderNode*> m_renderTargetRenderNodes;
  283. int m_renderTargetNestLevel = 0;
  284. #ifndef _RELEASE
  285. // A debug-only variable used to track whether the rendergraph was rebuilt this frame
  286. mutable bool m_wasBuiltThisFrame = false;
  287. AZ::u64 m_timeGraphLastBuiltMs = 0;
  288. #endif
  289. };
  290. }