You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
344 lines
14 KiB
C++
344 lines
14 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <IRenderer.h>
|
|
#include <LyShine/IRenderGraph.h>
|
|
#include <AzCore/Memory/PoolAllocator.h>
|
|
#include <AzCore/std/containers/stack.h>
|
|
#include <AzCore/std/containers/set.h>
|
|
#include <AzCore/Math/Color.h>
|
|
|
|
#include <Atom/RPI.Reflect/Image/Image.h>
|
|
#include <AtomCore/Instance/Instance.h>
|
|
|
|
#include "UiRenderer.h"
|
|
#ifndef _RELEASE
|
|
#include "LyShineDebug.h"
|
|
#endif
|
|
|
|
namespace LyShine
|
|
{
|
|
enum RenderNodeType
|
|
{
|
|
PrimitiveList,
|
|
Mask,
|
|
RenderTarget
|
|
};
|
|
|
|
enum class AlphaMaskType
|
|
{
|
|
None,
|
|
ModulateAlpha,
|
|
ModulateAlphaAndColor
|
|
};
|
|
|
|
// Abstract base class for nodes in the render graph
|
|
class RenderNode
|
|
{
|
|
public: // functions
|
|
RenderNode(RenderNodeType type) : m_type(type) {}
|
|
virtual ~RenderNode() {};
|
|
|
|
virtual void Render(UiRenderer* uiRenderer) = 0;
|
|
|
|
RenderNodeType GetType() const { return m_type; }
|
|
|
|
#ifndef _RELEASE
|
|
// A debug-only function useful for debugging
|
|
virtual void ValidateNode() = 0;
|
|
#endif
|
|
|
|
private: // data
|
|
RenderNodeType m_type;
|
|
};
|
|
|
|
// As we build the render graph we allocate a render node for each change in render state
|
|
class PrimitiveListRenderNode : public RenderNode
|
|
{
|
|
public: // functions
|
|
// We use a pool allocator to keep these allocations fast.
|
|
AZ_CLASS_ALLOCATOR(PrimitiveListRenderNode, AZ::PoolAllocator, 0);
|
|
|
|
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, int blendModeState);
|
|
PrimitiveListRenderNode(const AZ::Data::Instance<AZ::RPI::Image>& texture, const AZ::Data::Instance<AZ::RPI::Image>& maskTexture,
|
|
bool isClampTextureMode, bool isTextureSRGB, bool preMultiplyAlpha, AlphaMaskType alphaMaskType, int blendModeState);
|
|
~PrimitiveListRenderNode() override;
|
|
void Render(UiRenderer* uiRenderer) override;
|
|
|
|
void AddPrimitive(IRenderer::DynUiPrimitive* primitive);
|
|
IRenderer::DynUiPrimitiveList& GetPrimitives() const;
|
|
|
|
int GetOrAddTexture(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode);
|
|
int GetNumTextures() const { return m_numTextures; }
|
|
const AZ::Data::Instance<AZ::RPI::Image> GetTexture(int texIndex) const { return m_textures[texIndex].m_texture; }
|
|
bool GetTextureIsClampMode(int texIndex) const { return m_textures[texIndex].m_isClampTextureMode; }
|
|
|
|
bool GetIsTextureSRGB() const { return m_isTextureSRGB; }
|
|
int GetBlendModeState() const { return m_blendModeState; }
|
|
bool GetIsPremultiplyAlpha() const { return m_preMultiplyAlpha; }
|
|
AlphaMaskType GetAlphaMaskType() const { return m_alphaMaskType; }
|
|
|
|
bool HasSpaceToAddPrimitive(IRenderer::DynUiPrimitive* primitive) const;
|
|
|
|
// Search to see if this texture is already used by this texture unit, returns -1 if not used
|
|
int FindTexture(const AZ::Data::Instance<AZ::RPI::Image>& texture, bool isClampTextureMode) const;
|
|
|
|
#ifndef _RELEASE
|
|
// A debug-only function useful for debugging
|
|
void ValidateNode() override;
|
|
#endif
|
|
|
|
public: // data
|
|
static const int MaxTextures = 16;
|
|
|
|
private: // types
|
|
struct TextureUsage
|
|
{
|
|
AZ::Data::Instance<AZ::RPI::Image> m_texture;
|
|
bool m_isClampTextureMode;
|
|
};
|
|
|
|
private: // data
|
|
TextureUsage m_textures[MaxTextures];
|
|
int m_numTextures;
|
|
bool m_isTextureSRGB;
|
|
bool m_preMultiplyAlpha;
|
|
AlphaMaskType m_alphaMaskType;
|
|
int m_blendModeState;
|
|
int m_totalNumVertices;
|
|
int m_totalNumIndices;
|
|
|
|
IRenderer::DynUiPrimitiveList m_primitives;
|
|
};
|
|
|
|
// A mask render node handles using one set of render nodes to mask another set of render nodes
|
|
class MaskRenderNode : public RenderNode
|
|
{
|
|
public: // functions
|
|
// We use a pool allocator to keep these allocations fast.
|
|
AZ_CLASS_ALLOCATOR(MaskRenderNode, AZ::PoolAllocator, 0);
|
|
|
|
MaskRenderNode(MaskRenderNode* parentMask, bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront);
|
|
~MaskRenderNode() override;
|
|
|
|
void Render(UiRenderer* uiRenderer) override;
|
|
|
|
AZStd::vector<RenderNode*>& GetMaskRenderNodeList() { return m_maskRenderNodes; }
|
|
const AZStd::vector<RenderNode*>& GetMaskRenderNodeList() const { return m_maskRenderNodes; }
|
|
|
|
AZStd::vector<RenderNode*>& GetContentRenderNodeList() { return m_contentRenderNodes; }
|
|
const AZStd::vector<RenderNode*>& GetContentRenderNodeList() const { return m_contentRenderNodes; }
|
|
|
|
MaskRenderNode* GetParentMask() { return m_parentMask; }
|
|
|
|
//! if the mask has no content elements and is not drawing the mask primitives then there is no need to add a render node
|
|
bool IsMaskRedundant();
|
|
|
|
bool GetIsMaskingEnabled() const { return m_isMaskingEnabled; }
|
|
bool GetUseAlphaTest() const { return m_useAlphaTest; }
|
|
bool GetDrawBehind() const { return m_drawBehind; }
|
|
bool GetDrawInFront() const { return m_drawInFront; }
|
|
|
|
#ifndef _RELEASE
|
|
// A debug-only function useful for debugging
|
|
void ValidateNode() override;
|
|
#endif
|
|
|
|
private: // functions
|
|
void SetupBeforeRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState);
|
|
void SetupAfterRenderingMask(UiRenderer* uiRenderer, bool firstPass, UiRenderer::BaseState priorBaseState);
|
|
|
|
private: // data
|
|
AZStd::vector<RenderNode*> m_maskRenderNodes; //!< The render nodes used to render the mask shape
|
|
AZStd::vector<RenderNode*> m_contentRenderNodes; //!< The render nodes that are masked by this mask
|
|
|
|
MaskRenderNode* m_parentMask = nullptr; //! Used while building the render graph.
|
|
|
|
// flags that control the render behavior of the mask
|
|
bool m_isMaskingEnabled = true;
|
|
bool m_useAlphaTest = false;
|
|
bool m_drawBehind = false;
|
|
bool m_drawInFront = false;
|
|
};
|
|
|
|
// A render target render node renders its child render nodes to a given render target
|
|
class RenderTargetRenderNode : public RenderNode
|
|
{
|
|
public: // functions
|
|
// We use a pool allocator to keep these allocations fast.
|
|
AZ_CLASS_ALLOCATOR(RenderTargetRenderNode, AZ::PoolAllocator, 0);
|
|
|
|
RenderTargetRenderNode(RenderTargetRenderNode* parentRenderTarget, int renderTargetHandle,
|
|
SDepthTexture* renderTargetDepthSurface,
|
|
const AZ::Vector2& viewportTopLeft,
|
|
const AZ::Vector2& viewportSize,
|
|
const AZ::Color& clearColor,
|
|
int nestLevel);
|
|
~RenderTargetRenderNode() override;
|
|
|
|
void Render(UiRenderer* uiRenderer) override;
|
|
|
|
AZStd::vector<RenderNode*>& GetChildRenderNodeList() { return m_childRenderNodes; }
|
|
const AZStd::vector<RenderNode*>& GetChildRenderNodeList() const { return m_childRenderNodes; }
|
|
|
|
RenderTargetRenderNode* GetParentRenderTarget() { return m_parentRenderTarget; }
|
|
|
|
float GetViewportX() const { return m_viewportX; }
|
|
float GetViewportY() const { return m_viewportY; }
|
|
float GetViewportWidth() const { return m_viewportWidth; }
|
|
float GetViewportHeight() const { return m_viewportHeight; }
|
|
AZ::Color GetClearColor() const { return m_clearColor; }
|
|
|
|
const char* GetRenderTargetName() const;
|
|
|
|
#ifndef _RELEASE
|
|
// A debug-only function useful for debugging
|
|
void ValidateNode() override;
|
|
#endif
|
|
|
|
//! Used to sort a list of RenderTargetNodes for render order
|
|
static bool CompareNestLevelForSort(RenderTargetRenderNode* a, RenderTargetRenderNode* b);
|
|
|
|
private: // functions
|
|
|
|
private: // data
|
|
AZStd::vector<RenderNode*> m_childRenderNodes; //!< The render nodes to render to the render target
|
|
|
|
RenderTargetRenderNode* m_parentRenderTarget = nullptr; //! Used while building the render graph.
|
|
|
|
int m_renderTargetHandle = -1;
|
|
SDepthTexture* m_renderTargetDepthSurface = nullptr;
|
|
|
|
float m_viewportX = 0;
|
|
float m_viewportY = 0;
|
|
float m_viewportWidth = 0;
|
|
float m_viewportHeight = 0;
|
|
AZ::Color m_clearColor;
|
|
int m_nestLevel = 0;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// The RenderGraph is owned by the canvas component
|
|
class RenderGraph : public IRenderGraph
|
|
{
|
|
public:
|
|
|
|
RenderGraph();
|
|
~RenderGraph() override;
|
|
|
|
//! Free up all the memory and clear the lists
|
|
void ResetGraph();
|
|
|
|
// IRenderGraph
|
|
void BeginMask(bool isMaskingEnabled, bool useAlphaTest, bool drawBehind, bool drawInFront) override;
|
|
void StartChildrenForMask() override;
|
|
void EndMask() override;
|
|
|
|
void BeginRenderToTexture(int renderTargetHandle, SDepthTexture* renderTargetDepthSurface,
|
|
const AZ::Vector2& viewportTopLeft, const AZ::Vector2& viewportSize,
|
|
const AZ::Color& clearColor) override;
|
|
void EndRenderToTexture() override;
|
|
|
|
void AddPrimitive(IRenderer::DynUiPrimitive* primitive, ITexture* texture,
|
|
bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode) override;
|
|
|
|
void AddAlphaMaskPrimitive(IRenderer::DynUiPrimitive* primitive,
|
|
ITexture* texture, ITexture* maskTexture,
|
|
bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode) override;
|
|
|
|
IRenderer::DynUiPrimitive* GetDynamicQuadPrimitive(const AZ::Vector2* positions, uint32 packedColor) override;
|
|
|
|
bool IsRenderingToMask() const override;
|
|
void SetIsRenderingToMask(bool isRenderingToMask) override;
|
|
|
|
void PushAlphaFade(float alphaFadeValue) override;
|
|
void PushOverrideAlphaFade(float alphaFadeValue) override;
|
|
void PopAlphaFade() override;
|
|
float GetAlphaFade() const override;
|
|
// ~IRenderGraph
|
|
|
|
// LYSHINE_ATOM_TODO - this can be renamed back to AddPrimitive after removal of IRenderer from all UI components
|
|
void AddPrimitiveAtom(IRenderer::DynUiPrimitive* primitive, const AZ::Data::Instance<AZ::RPI::Image>& texture,
|
|
bool isClampTextureMode, bool isTextureSRGB, bool isTexturePremultipliedAlpha, BlendMode blendMode);
|
|
|
|
//! Render the display graph
|
|
void Render(UiRenderer* uiRenderer, const AZ::Vector2& viewportSize);
|
|
|
|
//! Set the dirty flag - this also resets the graph
|
|
void SetDirtyFlag(bool isDirty);
|
|
|
|
//! Get the dirty flag
|
|
bool GetDirtyFlag();
|
|
|
|
//! End the building of the graph
|
|
void FinalizeGraph();
|
|
|
|
//! Test whether the render graph contains any render nodes
|
|
bool IsEmpty();
|
|
|
|
#ifndef _RELEASE
|
|
// A debug-only function useful for debugging, not called but calls can be added during debugging
|
|
void ValidateGraph();
|
|
|
|
void GetDebugInfoRenderGraph(LyShineDebug::DebugInfoRenderGraph& info) const;
|
|
void GetDebugInfoRenderNodeList(
|
|
const AZStd::vector<RenderNode*>& renderNodeList,
|
|
LyShineDebug::DebugInfoRenderGraph& info,
|
|
AZStd::set<AZ::Data::Instance<AZ::RPI::Image>>& uniqueTextures) const;
|
|
|
|
void DebugReportDrawCalls(AZ::IO::HandleType fileHandle, LyShineDebug::DebugInfoDrawCallReport& reportInfo, void* context) const;
|
|
void DebugReportDrawCallsRenderNodeList(const AZStd::vector<RenderNode*>& renderNodeList, AZ::IO::HandleType fileHandle,
|
|
LyShineDebug::DebugInfoDrawCallReport& reportInfo, void* context, const AZStd::string& indent) const;
|
|
#endif
|
|
|
|
protected: // types
|
|
|
|
struct DynamicQuad
|
|
{
|
|
SVF_P2F_C4B_T2F_F4B m_quadVerts[4];
|
|
IRenderer::DynUiPrimitive m_primitive;
|
|
};
|
|
|
|
protected: // member functions
|
|
|
|
//! Given a blend mode and whether the shader will be outputing premultiplied alpha, return state flags
|
|
int GetBlendModeState(LyShine::BlendMode blendMode, bool isShaderOutputPremultAlpha) const;
|
|
|
|
protected: // data
|
|
|
|
AZStd::vector<RenderNode*> m_renderNodes;
|
|
AZStd::vector<DynamicQuad*> m_dynamicQuads; // used for drawing quads not cached in components
|
|
|
|
MaskRenderNode* m_currentMask = nullptr;
|
|
RenderTargetRenderNode* m_currentRenderTarget = nullptr;
|
|
|
|
AZStd::stack<AZStd::vector<RenderNode*>*> m_renderNodeListStack;
|
|
|
|
bool m_isDirty = true;
|
|
int m_renderToRenderTargetCount = 0;
|
|
|
|
bool m_isRenderingToMask = false;
|
|
AZStd::stack<float> m_alphaFadeStack;
|
|
|
|
AZStd::vector<RenderTargetRenderNode*> m_renderTargetRenderNodes;
|
|
int m_renderTargetNestLevel = 0;
|
|
|
|
#ifndef _RELEASE
|
|
// A debug-only variable used to track whether the rendergraph was rebuilt this frame
|
|
mutable bool m_wasBuiltThisFrame = false;
|
|
AZ::u64 m_timeGraphLastBuiltMs = 0;
|
|
#endif
|
|
};
|
|
}
|