//--------------------------------------------------------------------------------------
// File: Effect.h
//
//  Direct3D 11 Effects Header for ID3DX11Effect Implementation
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// http://go.microsoft.com/fwlink/p/?LinkId=271568
//--------------------------------------------------------------------------------------

#pragma once

#include "EffectBinaryFormat.h"
#include "IUnknownImp.h"

#ifdef _DEBUG
extern void __cdecl D3DXDebugPrintf(UINT lvl, _In_z_ _Printf_format_string_ LPCSTR szFormat, ...);
#define DPF D3DXDebugPrintf
#else
#define DPF
#endif

#pragma warning(push)
#pragma warning(disable : 4481)
// VS 2010 considers 'override' to be a extension, but it's part of C++11 as of VS 2012

//////////////////////////////////////////////////////////////////////////

using namespace D3DX11Core;

namespace D3DX11Effects
{

//////////////////////////////////////////////////////////////////////////
// Forward defines
//////////////////////////////////////////////////////////////////////////

struct SBaseBlock;
struct SShaderBlock;
struct SPassBlock;
struct SClassInstance;
struct SInterface;
struct SShaderResource;
struct SUnorderedAccessView;
struct SRenderTargetView;
struct SDepthStencilView;
struct SSamplerBlock;
struct SDepthStencilBlock;
struct SBlendBlock;
struct SRasterizerBlock;
struct SString;
struct SD3DShaderVTable;
struct SClassInstanceGlobalVariable;

struct SAssignment;
struct SVariable;
struct SGlobalVariable;
struct SAnnotation;
struct SConstantBuffer;

class CEffect;
class CEffectLoader;

enum ELhsType;

// Allows the use of 32-bit and 64-bit timers depending on platform type
typedef size_t Timer;

//////////////////////////////////////////////////////////////////////////
// Reflection & Type structures
//////////////////////////////////////////////////////////////////////////

// CEffectMatrix is used internally instead of float arrays
struct CEffectMatrix 
{
    union 
    {
        struct 
        {
            float        _11, _12, _13, _14;
            float        _21, _22, _23, _24;
            float        _31, _32, _33, _34;
            float        _41, _42, _43, _44;

        };
        float m[4][4];
    };
};

struct CEffectVector4 
{
    float x;
    float y;
    float z;
    float w;
};

union UDataPointer
{
    void                    *pGeneric;
    uint8_t                 *pNumeric; 
    float                   *pNumericFloat;
    uint32_t                *pNumericDword;
    int                     *pNumericInt;
    BOOL                    *pNumericBool;
    SString                 *pString;
    SShaderBlock            *pShader;
    SBaseBlock              *pBlock;
    SBlendBlock             *pBlend;
    SDepthStencilBlock      *pDepthStencil;
    SRasterizerBlock        *pRasterizer;
    SInterface              *pInterface;
    SShaderResource         *pShaderResource;
    SUnorderedAccessView    *pUnorderedAccessView;
    SRenderTargetView       *pRenderTargetView;
    SDepthStencilView       *pDepthStencilView;
    SSamplerBlock           *pSampler;
    CEffectVector4          *pVector;
    CEffectMatrix           *pMatrix;
    UINT_PTR                Offset;
};

enum EMemberDataType
{
    MDT_ClassInstance,
    MDT_BlendState,
    MDT_DepthStencilState,
    MDT_RasterizerState,
    MDT_SamplerState,
    MDT_Buffer,
    MDT_ShaderResourceView,
};

struct SMemberDataPointer
{
    EMemberDataType             Type;
    union
    {
        IUnknown                *pGeneric;
        ID3D11ClassInstance     *pD3DClassInstance;
        ID3D11BlendState        *pD3DEffectsManagedBlendState;
        ID3D11DepthStencilState *pD3DEffectsManagedDepthStencilState;
        ID3D11RasterizerState   *pD3DEffectsManagedRasterizerState;
        ID3D11SamplerState      *pD3DEffectsManagedSamplerState;
        ID3D11Buffer            *pD3DEffectsManagedConstantBuffer;
        ID3D11ShaderResourceView*pD3DEffectsManagedTextureBuffer;
    } Data;
};

struct SType : public ID3DX11EffectType
{   
    static const UINT_PTR c_InvalidIndex = (uint32_t) -1;
    static const uint32_t c_ScalarSize = sizeof(uint32_t);

    // packing rule constants
    static const uint32_t c_ScalarsPerRegister = 4;
    static const uint32_t c_RegisterSize = c_ScalarsPerRegister * c_ScalarSize; // must be a power of 2!!    
    
    EVarType    VarType;        // numeric, object, struct
    uint32_t    Elements;       // # of array elements (0 for non-arrays)
    char        *pTypeName;     // friendly name of the type: "VS_OUTPUT", "float4", etc.

    // *Size and stride values are always 0 for object types
    // *Annotations adhere to packing rules (even though they do not reside in constant buffers)
    //      for consistency's sake
    //
    // Packing rules:
    // *Structures and array elements are always register aligned
    // *Single-row values (or, for column major matrices, single-column) are greedily
    //  packed unless doing so would span a register boundary, in which case they are
    //  register aligned

    uint32_t    TotalSize;      // Total size of this data type in a constant buffer from
                                // start to finish (padding in between elements is included,
                                // but padding at the end is not since that would require
                                // knowledge of the following data type).

    uint32_t    Stride;         // Number of bytes to advance between elements.
                                // Typically a multiple of 16 for arrays, vectors, matrices.
                                // For scalars and small vectors/matrices, this can be 4 or 8.    

    uint32_t    PackedSize;     // Size, in bytes, of this data typed when fully packed

    union
    {        
        SBinaryNumericType  NumericType;
        EObjectType         ObjectType;         // not all values of EObjectType are valid here (e.g. constant buffer)
        struct
        {
            SVariable   *pMembers;              // array of type instances describing structure members
            uint32_t    Members;
            BOOL        ImplementsInterface;    // true if this type implements an interface
            BOOL        HasSuperClass;          // true if this type has a parent class
        }               StructType;
        void*           InterfaceType;          // nothing for interfaces
    };


    SType() :
       VarType(EVT_Invalid),
       Elements(0),
       pTypeName(nullptr),
       TotalSize(0),
       Stride(0),
       PackedSize(0)
    {
        C_ASSERT( sizeof(NumericType) <= sizeof(StructType) );
        C_ASSERT( sizeof(ObjectType) <= sizeof(StructType) );
        C_ASSERT( sizeof(InterfaceType) <= sizeof(StructType) );
        ZeroMemory( &StructType, sizeof(StructType) );
    }

    bool IsEqual(SType *pOtherType) const;
    
    bool IsObjectType(EObjectType ObjType) const
    {
        return IsObjectTypeHelper(VarType, ObjectType, ObjType);
    }
    bool IsShader() const
    {
        return IsShaderHelper(VarType, ObjectType);
    }
    bool BelongsInConstantBuffer() const
    {
        return (VarType == EVT_Numeric) || (VarType == EVT_Struct);
    }
    bool IsStateBlockObject() const
    {
        return IsStateBlockObjectHelper(VarType, ObjectType);
    }
    bool IsClassInstance() const
    {
        return (VarType == EVT_Struct) && StructType.ImplementsInterface;
    }
    bool IsInterface() const
    {
        return IsInterfaceHelper(VarType, ObjectType);
    }
    bool IsShaderResource() const
    {
        return IsShaderResourceHelper(VarType, ObjectType);
    }
    bool IsUnorderedAccessView() const
    {
        return IsUnorderedAccessViewHelper(VarType, ObjectType);
    }
    bool IsSampler() const
    {
        return IsSamplerHelper(VarType, ObjectType);
    }
    bool IsRenderTargetView() const
    {
        return IsRenderTargetViewHelper(VarType, ObjectType);
    }
    bool IsDepthStencilView() const
    {
        return IsDepthStencilViewHelper(VarType, ObjectType);
    }

    uint32_t GetTotalUnpackedSize(_In_ bool IsSingleElement) const; 
    uint32_t GetTotalPackedSize(_In_ bool IsSingleElement) const; 
    HRESULT GetDescHelper(_Out_ D3DX11_EFFECT_TYPE_DESC *pDesc, _In_ bool IsSingleElement) const;

    STDMETHOD_(bool, IsValid)() override { return true; }
    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_TYPE_DESC *pDesc) override { return GetDescHelper(pDesc, false); }
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByName)(_In_z_ LPCSTR Name) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeBySemantic)(_In_z_ LPCSTR Semantic) override;
    STDMETHOD_(LPCSTR, GetMemberName)(_In_ uint32_t Index) override;
    STDMETHOD_(LPCSTR, GetMemberSemantic)(_In_ uint32_t Index) override;

    IUNKNOWN_IMP(SType, ID3DX11EffectType, IUnknown);
};

// Represents a type structure for a single element.
// It seems pretty trivial, but it has a different virtual table which enables
// us to accurately represent a type that consists of a single element
struct SSingleElementType : public ID3DX11EffectType
{
    SType *pType;

    STDMETHOD_(bool, IsValid)() override { return true; }
    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_TYPE_DESC *pDesc) override { return ((SType*)pType)->GetDescHelper(pDesc, true); }
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByIndex)(uint32_t Index) override { return ((SType*)pType)->GetMemberTypeByIndex(Index); }
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByName)(LPCSTR Name) override { return ((SType*)pType)->GetMemberTypeByName(Name); }
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeBySemantic)(LPCSTR Semantic) override { return ((SType*)pType)->GetMemberTypeBySemantic(Semantic); }
    STDMETHOD_(LPCSTR, GetMemberName)(uint32_t Index) override { return ((SType*)pType)->GetMemberName(Index); }
    STDMETHOD_(LPCSTR, GetMemberSemantic)(uint32_t Index) override { return ((SType*)pType)->GetMemberSemantic(Index); }

    IUNKNOWN_IMP(SSingleElementType, ID3DX11EffectType, IUnknown);
};

//////////////////////////////////////////////////////////////////////////
// Block definitions
//////////////////////////////////////////////////////////////////////////

void * GetBlockByIndex(EVarType VarType, EObjectType ObjectType, void *pBaseBlock, uint32_t Index);

struct SBaseBlock
{
    EBlockType      BlockType;

    bool            IsUserManaged:1;

    uint32_t        AssignmentCount;
    SAssignment     *pAssignments;

    SBaseBlock();

    bool ApplyAssignments(CEffect *pEffect);

    inline SSamplerBlock *AsSampler() const
    {
        assert( BlockType == EBT_Sampler );
        return (SSamplerBlock*) this;
    }

    inline SDepthStencilBlock *AsDepthStencil() const
    {
        assert( BlockType == EBT_DepthStencil );
        return (SDepthStencilBlock*) this;
    }

    inline SBlendBlock *AsBlend() const
    {
        assert( BlockType == EBT_Blend );
        return (SBlendBlock*) this;
    }

    inline SRasterizerBlock *AsRasterizer() const
    {
        assert( BlockType == EBT_Rasterizer );
        return (SRasterizerBlock*) this;
    }

    inline SPassBlock *AsPass() const
    {
        assert( BlockType == EBT_Pass );
        return (SPassBlock*) this;
    }
};

struct STechnique : public ID3DX11EffectTechnique
{
    char        *pName;

    uint32_t    PassCount;
    SPassBlock  *pPasses;

    uint32_t    AnnotationCount;
    SAnnotation *pAnnotations;

    bool        InitiallyValid;
    bool        HasDependencies;

    STechnique();

    STDMETHOD_(bool, IsValid)() override;
    STDMETHOD(GetDesc)(_Out_ D3DX11_TECHNIQUE_DESC *pDesc) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3DX11EffectPass*, GetPassByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectPass*, GetPassByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD(ComputeStateBlockMask)(_Inout_ D3DX11_STATE_BLOCK_MASK *pStateBlockMask) override;

    IUNKNOWN_IMP(STechnique, ID3DX11EffectTechnique, IUnknown);
};

struct SGroup : public ID3DX11EffectGroup
{
    char        *pName;

    uint32_t    TechniqueCount;
    STechnique  *pTechniques;

    uint32_t    AnnotationCount;
    SAnnotation *pAnnotations;

    bool        InitiallyValid;
    bool        HasDependencies;

    SGroup();

    STDMETHOD_(bool, IsValid)() override;
    STDMETHOD(GetDesc)(_Out_ D3DX11_GROUP_DESC *pDesc) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3DX11EffectTechnique*, GetTechniqueByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectTechnique*, GetTechniqueByName)(_In_z_ LPCSTR Name) override;

    IUNKNOWN_IMP(SGroup, ID3DX11EffectGroup, IUnknown);
};

struct SPassBlock : SBaseBlock, public ID3DX11EffectPass
{
    struct
    {
        ID3D11BlendState*       pBlendState;
        FLOAT                   BlendFactor[4];
        uint32_t                SampleMask;
        ID3D11DepthStencilState *pDepthStencilState;
        uint32_t                StencilRef;
        union
        {
            D3D11_SO_DECLARATION_ENTRY  *pEntry;
            char                        *pEntryDesc;
        }                       GSSODesc;

        // Pass assignments can write directly into these
        SBlendBlock             *pBlendBlock;
        SDepthStencilBlock      *pDepthStencilBlock;
        SRasterizerBlock        *pRasterizerBlock;
        uint32_t                RenderTargetViewCount;
        SRenderTargetView       *pRenderTargetViews[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
        SDepthStencilView       *pDepthStencilView;
        SShaderBlock            *pVertexShaderBlock;
        SShaderBlock            *pPixelShaderBlock;
        SShaderBlock            *pGeometryShaderBlock;
        SShaderBlock            *pComputeShaderBlock;
        SShaderBlock            *pDomainShaderBlock;
        SShaderBlock            *pHullShaderBlock;
    }           BackingStore;

    char        *pName;

    uint32_t    AnnotationCount;
    SAnnotation *pAnnotations;

    CEffect     *pEffect;

    bool        InitiallyValid;         // validity of all state objects and shaders in pass upon BindToDevice
    bool        HasDependencies;        // if pass expressions or pass state blocks have dependencies on variables (if true, IsValid != InitiallyValid possibly)

    SPassBlock();

    void ApplyPassAssignments();
    bool CheckShaderDependencies( _In_ const SShaderBlock* pBlock );
    bool CheckDependencies();

    template<EObjectType EShaderType>
    HRESULT GetShaderDescHelper(_Out_ D3DX11_PASS_SHADER_DESC *pDesc);

    STDMETHOD_(bool, IsValid)() override;
    STDMETHOD(GetDesc)(_Out_ D3DX11_PASS_DESC *pDesc) override;

    STDMETHOD(GetVertexShaderDesc)(_Out_ D3DX11_PASS_SHADER_DESC *pDesc) override;
    STDMETHOD(GetGeometryShaderDesc)(_Out_ D3DX11_PASS_SHADER_DESC *pDesc) override;
    STDMETHOD(GetPixelShaderDesc)(_Out_ D3DX11_PASS_SHADER_DESC *pDesc) override;
    STDMETHOD(GetHullShaderDesc)(_Out_ D3DX11_PASS_SHADER_DESC *pDesc) override;
    STDMETHOD(GetDomainShaderDesc)(_Out_ D3DX11_PASS_SHADER_DESC *pDesc) override;
    STDMETHOD(GetComputeShaderDesc)(_Out_ D3DX11_PASS_SHADER_DESC *pDesc) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD(Apply)(_In_ uint32_t Flags, _In_ ID3D11DeviceContext* pContext) override;
    
    STDMETHOD(ComputeStateBlockMask)(_Inout_ D3DX11_STATE_BLOCK_MASK *pStateBlockMask) override;

    IUNKNOWN_IMP(SPassBlock, ID3DX11EffectPass, IUnknown);
};

struct SDepthStencilBlock : SBaseBlock
{
    ID3D11DepthStencilState *pDSObject;
    D3D11_DEPTH_STENCIL_DESC BackingStore;
    bool                     IsValid;

    SDepthStencilBlock();
};

struct SBlendBlock : SBaseBlock
{
    ID3D11BlendState        *pBlendObject;
    D3D11_BLEND_DESC        BackingStore;
    bool                    IsValid;

    SBlendBlock();
};

struct SRasterizerBlock : SBaseBlock
{
    ID3D11RasterizerState   *pRasterizerObject;
    D3D11_RASTERIZER_DESC   BackingStore;
    bool                    IsValid;

    SRasterizerBlock();
};

struct SSamplerBlock : SBaseBlock
{
    ID3D11SamplerState      *pD3DObject;
    struct
    {
        D3D11_SAMPLER_DESC  SamplerDesc;
        // Sampler "TEXTURE" assignments can write directly into this
        SShaderResource     *pTexture;
    } BackingStore;

    SSamplerBlock();
};

struct SInterface
{
    SClassInstanceGlobalVariable* pClassInstance;

    SInterface()
    {
        pClassInstance = nullptr;
    }
};

struct SShaderResource
{
    ID3D11ShaderResourceView *pShaderResource;

    SShaderResource() 
    {
        pShaderResource = nullptr;
    }

};

struct SUnorderedAccessView
{
    ID3D11UnorderedAccessView *pUnorderedAccessView;

    SUnorderedAccessView() 
    {
        pUnorderedAccessView = nullptr;
    }

};

struct SRenderTargetView
{
    ID3D11RenderTargetView *pRenderTargetView;

    SRenderTargetView();
};

struct SDepthStencilView
{
    ID3D11DepthStencilView *pDepthStencilView;

    SDepthStencilView();
};


template<class T, class D3DTYPE> struct SShaderDependency
{
    uint32_t    StartIndex;
    uint32_t    Count;

    T       *ppFXPointers;              // Array of ptrs to FX objects (CBs, SShaderResources, etc)
    D3DTYPE *ppD3DObjects;              // Array of ptrs to matching D3D objects

    SShaderDependency()
    {
        StartIndex = Count = 0;

        ppD3DObjects = nullptr;
        ppFXPointers = nullptr;
    }
};

typedef SShaderDependency<SConstantBuffer*, ID3D11Buffer*> SShaderCBDependency;
typedef SShaderDependency<SSamplerBlock*, ID3D11SamplerState*> SShaderSamplerDependency;
typedef SShaderDependency<SShaderResource*, ID3D11ShaderResourceView*> SShaderResourceDependency;
typedef SShaderDependency<SUnorderedAccessView*, ID3D11UnorderedAccessView*> SUnorderedAccessViewDependency;
typedef SShaderDependency<SInterface*, ID3D11ClassInstance*> SInterfaceDependency;

// Shader VTables are used to eliminate branching in ApplyShaderBlock.
// The effect owns one D3DShaderVTables for each shader stage
struct SD3DShaderVTable
{
    void ( __stdcall ID3D11DeviceContext::*pSetShader)(ID3D11DeviceChild* pShader, ID3D11ClassInstance*const* ppClassInstances, uint32_t NumClassInstances);
    void ( __stdcall ID3D11DeviceContext::*pSetConstantBuffers)(uint32_t StartConstantSlot, uint32_t NumBuffers, ID3D11Buffer *const *pBuffers);
    void ( __stdcall ID3D11DeviceContext::*pSetSamplers)(uint32_t Offset, uint32_t NumSamplers, ID3D11SamplerState*const* pSamplers);
    void ( __stdcall ID3D11DeviceContext::*pSetShaderResources)(uint32_t Offset, uint32_t NumResources, ID3D11ShaderResourceView *const *pResources);
    HRESULT ( __stdcall ID3D11Device::*pCreateShader)(const void *pShaderBlob, size_t ShaderBlobSize, ID3D11ClassLinkage* pClassLinkage, ID3D11DeviceChild **ppShader);
};


struct SShaderBlock
{
    enum ESigType
    {
        ST_Input,
        ST_Output,
        ST_PatchConstant,
    };

    struct SInterfaceParameter
    {
        char                        *pName;
        uint32_t                        Index;
    };

    // this data is classified as reflection-only and will all be discarded at runtime
    struct SReflectionData
    {
        uint8_t                     *pBytecode;
        uint32_t                    BytecodeLength;
        char                        *pStreamOutDecls[4];        // set with ConstructGSWithSO
        uint32_t                    RasterizedStream;           // set with ConstructGSWithSO
        BOOL                        IsNullGS;
        ID3D11ShaderReflection      *pReflection;
        uint32_t                    InterfaceParameterCount;    // set with BindInterfaces (used for function interface parameters)
        SInterfaceParameter         *pInterfaceParameters;      // set with BindInterfaces (used for function interface parameters)
    };

    bool                            IsValid;
    SD3DShaderVTable                *pVT;                

    // This value is nullptr if the shader is nullptr or was never initialized
    SReflectionData                 *pReflectionData;

    ID3D11DeviceChild               *pD3DObject;

    uint32_t                        CBDepCount;
    SShaderCBDependency             *pCBDeps;

    uint32_t                        SampDepCount;
    SShaderSamplerDependency        *pSampDeps;

    uint32_t                        InterfaceDepCount;
    SInterfaceDependency            *pInterfaceDeps;

    uint32_t                        ResourceDepCount;
    SShaderResourceDependency       *pResourceDeps;

    uint32_t                        UAVDepCount;
    SUnorderedAccessViewDependency  *pUAVDeps;

    uint32_t                        TBufferDepCount;
    SConstantBuffer                 **ppTbufDeps;

    ID3DBlob                        *pInputSignatureBlob;   // The input signature is separated from the bytecode because it 
                                                            // is always available, even after Optimize() has been called.

    SShaderBlock(SD3DShaderVTable *pVirtualTable = nullptr);

    EObjectType GetShaderType();

    HRESULT OnDeviceBind();

    // Public API helpers
    HRESULT ComputeStateBlockMask(_Inout_ D3DX11_STATE_BLOCK_MASK *pStateBlockMask);

    HRESULT GetShaderDesc(_Out_ D3DX11_EFFECT_SHADER_DESC *pDesc, _In_ bool IsInline);

    HRESULT GetVertexShader(_Outptr_ ID3D11VertexShader **ppVS);
    HRESULT GetGeometryShader(_Outptr_ ID3D11GeometryShader **ppGS);
    HRESULT GetPixelShader(_Outptr_ ID3D11PixelShader **ppPS);
    HRESULT GetHullShader(_Outptr_ ID3D11HullShader **ppHS);
    HRESULT GetDomainShader(_Outptr_ ID3D11DomainShader **ppDS);
    HRESULT GetComputeShader(_Outptr_ ID3D11ComputeShader **ppCS);

    HRESULT GetSignatureElementDesc(_In_ ESigType SigType, _In_ uint32_t Element, _Out_ D3D11_SIGNATURE_PARAMETER_DESC *pDesc);
};



struct SString
{
    char *pString;

    SString();
};



//////////////////////////////////////////////////////////////////////////
// Global Variable & Annotation structure/interface definitions
//////////////////////////////////////////////////////////////////////////

//
// This is a general structure that can describe
// annotations, variables, and structure members
//
struct SVariable
{
    // For annotations/variables/variable members:
    // 1) If numeric, pointer to data (for variables: points into backing store,
    //      for annotations, points into reflection heap)
    // OR
    // 2) If object, pointer to the block. If object array, subsequent array elements are found in
    //      contiguous blocks; the Nth block is found by ((<SpecificBlockType> *) pBlock) + N
    //      (this is because variables that are arrays of objects have their blocks allocated contiguously)
    //
    // For structure members:
    //    Offset of this member (in bytes) from parent structure (structure members must be numeric/struct)
    UDataPointer            Data;
    union
    {
        uint32_t            MemberDataOffsetPlus4;  // 4 added so that 0 == nullptr can represent "unused"
        SMemberDataPointer  *pMemberData;
    };

    SType                   *pType;
    char                    *pName;
    char                    *pSemantic;
    uint32_t                ExplicitBindPoint;

    SVariable()
    {
        ZeroMemory(this, sizeof(*this));
        ExplicitBindPoint = uint32_t(-1);
    }
};

// Template definitions for all of the various ID3DX11EffectVariable specializations
#include "EffectVariable.inl"


////////////////////////////////////////////////////////////////////////////////
// ID3DX11EffectShaderVariable (SAnonymousShader implementation)
////////////////////////////////////////////////////////////////////////////////

struct SAnonymousShader : public TUncastableVariable<ID3DX11EffectShaderVariable>, public ID3DX11EffectType
{
    SShaderBlock    *pShaderBlock;

    SAnonymousShader(_In_ SShaderBlock *pBlock = nullptr);

    // ID3DX11EffectShaderVariable interface
    STDMETHOD_(bool, IsValid)() override;
    STDMETHOD_(ID3DX11EffectType*, GetType)() override;
    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_VARIABLE_DESC *pDesc) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetMemberByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetMemberByName)(_In_z_ LPCSTR Name) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetMemberBySemantic)(_In_z_ LPCSTR Semantic) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetElement)(_In_ uint32_t Index) override;

    STDMETHOD_(ID3DX11EffectConstantBuffer*, GetParentConstantBuffer)() override;

    // other casts are handled by TUncastableVariable
    STDMETHOD_(ID3DX11EffectShaderVariable*, AsShader)() override;

    STDMETHOD(SetRawValue)(_In_reads_bytes_(Count) const void *pData, _In_ uint32_t Offset, _In_ uint32_t Count) override;
    STDMETHOD(GetRawValue)(_Out_writes_bytes_(Count) void *pData, _In_ uint32_t Offset, _In_ uint32_t Count) override;

    STDMETHOD(GetShaderDesc)(_In_ uint32_t ShaderIndex, _Out_ D3DX11_EFFECT_SHADER_DESC *pDesc) override;

    STDMETHOD(GetVertexShader)(_In_ uint32_t ShaderIndex, _Outptr_ ID3D11VertexShader **ppVS) override;
    STDMETHOD(GetGeometryShader)(_In_ uint32_t ShaderIndex, _Outptr_ ID3D11GeometryShader **ppGS) override;
    STDMETHOD(GetPixelShader)(_In_ uint32_t ShaderIndex, _Outptr_ ID3D11PixelShader **ppPS) override;
    STDMETHOD(GetHullShader)(_In_ uint32_t ShaderIndex, _Outptr_ ID3D11HullShader **ppHS) override;
    STDMETHOD(GetDomainShader)(_In_ uint32_t ShaderIndex, _Outptr_ ID3D11DomainShader **ppDS) override;
    STDMETHOD(GetComputeShader)(_In_ uint32_t ShaderIndex, _Outptr_ ID3D11ComputeShader **ppCS) override;

    STDMETHOD(GetInputSignatureElementDesc)(_In_ uint32_t ShaderIndex, _In_ uint32_t Element, _Out_ D3D11_SIGNATURE_PARAMETER_DESC *pDesc) override;
    STDMETHOD(GetOutputSignatureElementDesc)(_In_ uint32_t ShaderIndex, _In_ uint32_t Element, _Out_ D3D11_SIGNATURE_PARAMETER_DESC *pDesc) override;
    STDMETHOD(GetPatchConstantSignatureElementDesc)(_In_ uint32_t ShaderIndex, _In_ uint32_t Element, _Out_ D3D11_SIGNATURE_PARAMETER_DESC *pDesc) override;

    // ID3DX11EffectType interface
    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_TYPE_DESC *pDesc) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByName)(_In_z_ LPCSTR Name) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeBySemantic)(_In_z_ LPCSTR Semantic) override;

    STDMETHOD_(LPCSTR, GetMemberName)(_In_ uint32_t Index) override;
    STDMETHOD_(LPCSTR, GetMemberSemantic)(_In_ uint32_t Index) override;

    IUNKNOWN_IMP(SAnonymousShader, ID3DX11EffectShaderVariable, ID3DX11EffectVariable);
};

////////////////////////////////////////////////////////////////////////////////
// ID3DX11EffectConstantBuffer (SConstantBuffer implementation)
////////////////////////////////////////////////////////////////////////////////

struct SConstantBuffer : public TUncastableVariable<ID3DX11EffectConstantBuffer>, public ID3DX11EffectType
{
    ID3D11Buffer            *pD3DObject;
    SShaderResource         TBuffer;            // nullptr iff IsTbuffer == false

    uint8_t                 *pBackingStore;
    uint32_t                Size;               // in bytes

    char                    *pName;

    uint32_t                AnnotationCount;
    SAnnotation             *pAnnotations;

    uint32_t                VariableCount;      // # of variables contained in this cbuffer
    SGlobalVariable         *pVariables;        // array of size [VariableCount], points into effect's contiguous variable list
    uint32_t                ExplicitBindPoint;  // Used when a CB has been explicitly bound (register(bXX)). -1 if not

    bool                    IsDirty:1;          // Set when any member is updated; cleared on CB apply    
    bool                    IsTBuffer:1;        // true iff TBuffer.pShaderResource != nullptr
    bool                    IsUserManaged:1;    // Set if you don't want effects to update this buffer
    bool                    IsEffectOptimized:1;// Set if the effect has been optimized
    bool                    IsUsedByExpression:1;// Set if used by any expressions
    bool                    IsUserPacked:1;     // Set if the elements have user-specified offsets
    bool                    IsSingle:1;         // Set to true if you want to share this CB with cloned Effects
    bool                    IsNonUpdatable:1;   // Set to true if you want to share this CB with cloned Effects

    union
    {
        // These are used to store the original ID3D11Buffer* for use in UndoSetConstantBuffer
        uint32_t            MemberDataOffsetPlus4;  // 4 added so that 0 == nullptr can represent "unused"
        SMemberDataPointer  *pMemberData;
    };

    CEffect                 *pEffect;

    SConstantBuffer()
    {
        pD3DObject = nullptr;
        ZeroMemory(&TBuffer, sizeof(TBuffer));
        ExplicitBindPoint = uint32_t(-1);
        pBackingStore = nullptr;
        Size = 0;
        pName = nullptr;
        VariableCount = 0;
        pVariables = nullptr;
        AnnotationCount = 0;
        pAnnotations = nullptr;
        IsDirty = false;
        IsTBuffer = false;
        IsUserManaged = false;
        IsEffectOptimized = false;
        IsUsedByExpression = false;
        IsUserPacked = false;
        IsSingle = false;
        IsNonUpdatable = false;
        pEffect = nullptr;
    }

    bool ClonedSingle() const;

    // ID3DX11EffectConstantBuffer interface
    STDMETHOD_(bool, IsValid)() override;
    STDMETHOD_(ID3DX11EffectType*, GetType)() override;
    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_VARIABLE_DESC *pDesc) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetAnnotationByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetMemberByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetMemberByName)(_In_z_ LPCSTR Name) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetMemberBySemantic)(_In_z_ LPCSTR Semantic) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetElement)(_In_ uint32_t Index) override;

    STDMETHOD_(ID3DX11EffectConstantBuffer*, GetParentConstantBuffer)() override;

    // other casts are handled by TUncastableVariable
    STDMETHOD_(ID3DX11EffectConstantBuffer*, AsConstantBuffer)() override;

    STDMETHOD(SetRawValue)(_In_reads_bytes_(Count) const void *pData, _In_ uint32_t Offset, _In_ uint32_t Count) override;
    STDMETHOD(GetRawValue)(_Out_writes_bytes_(Count) void *pData, _In_ uint32_t Offset, _In_ uint32_t Count) override;

    STDMETHOD(SetConstantBuffer)(_In_ ID3D11Buffer *pConstantBuffer) override;
    STDMETHOD(GetConstantBuffer)(_Outptr_ ID3D11Buffer **ppConstantBuffer) override;
    STDMETHOD(UndoSetConstantBuffer)() override;

    STDMETHOD(SetTextureBuffer)(_In_ ID3D11ShaderResourceView *pTextureBuffer) override;
    STDMETHOD(GetTextureBuffer)(_Outptr_ ID3D11ShaderResourceView **ppTextureBuffer) override;
    STDMETHOD(UndoSetTextureBuffer)() override;

    // ID3DX11EffectType interface
    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_TYPE_DESC *pDesc) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeByName)(_In_z_ LPCSTR Name) override;
    STDMETHOD_(ID3DX11EffectType*, GetMemberTypeBySemantic)(_In_z_ LPCSTR Semantic) override;

    STDMETHOD_(LPCSTR, GetMemberName)(_In_ uint32_t Index) override;
    STDMETHOD_(LPCSTR, GetMemberSemantic)(_In_ uint32_t Index) override;

    IUNKNOWN_IMP(SConstantBuffer, ID3DX11EffectConstantBuffer, ID3DX11EffectVariable);
};


//////////////////////////////////////////////////////////////////////////
// Assignments
//////////////////////////////////////////////////////////////////////////

enum ERuntimeAssignmentType
{
    ERAT_Invalid,
    // [Destination] refers to the destination location, which is always the backing store of the pass/state block. 
    // [Source] refers to the current source of data, always coming from either a constant buffer's 
    //  backing store (for numeric assignments), an object variable's block array, or an anonymous (unowned) block

    // Numeric variables:
    ERAT_Constant,                  // Source is unused.
                                    // No dependencies; this assignment can be safely removed after load.
    ERAT_NumericVariable,           // Source points to the CB's backing store where the value lives.
                                    // 1 dependency: the variable itself.
    ERAT_NumericConstIndex,         // Source points to the CB's backing store where the value lives, offset by N.
                                    // 1 dependency: the variable array being indexed.
    ERAT_NumericVariableIndex,      // Source points to the last used element of the variable in the CB's backing store.
                                    // 2 dependencies: the index variable followed by the array variable.

    // Object variables:
    ERAT_ObjectInlineShader,        // An anonymous, immutable shader block pointer is copied to the destination immediately.
                                    // No dependencies; this assignment can be safely removed after load.
    ERAT_ObjectVariable,            // A pointer to the block owned by the object variable is copied to the destination immediately.
                                    // No dependencies; this assignment can be safely removed after load.
    ERAT_ObjectConstIndex,          // A pointer to the Nth block owned by an object variable is copied to the destination immediately.
                                    // No dependencies; this assignment can be safely removed after load.
    ERAT_ObjectVariableIndex,       // Source points to the first block owned by an object variable array
                                    // (the offset from this, N, is taken from another variable).
                                    // 1 dependency: the variable being used to index the array.
};

struct SAssignment
{
    struct SDependency
    {
        SGlobalVariable *pVariable;

        SDependency()
        {
            pVariable = nullptr;
        }
    };

    ELhsType                LhsType;            // PS, VS, DepthStencil etc.

    // The value of SAssignment.AssignmentType determines how the other fields behave
    // (DependencyCount, pDependencies, Destination, and Source)
    ERuntimeAssignmentType  AssignmentType;      

    Timer                   LastRecomputedTime;

    // see comments in ERuntimeAssignmentType for how dependencies and data pointers are handled
    uint32_t                DependencyCount;
    SDependency             *pDependencies;

    UDataPointer            Destination;        // This value never changes after load, and always refers to the backing store
    UDataPointer            Source;             // This value, on the other hand, can change if variable- or expression- driven

    uint32_t                DataSize : 16;      // Size of the data element to be copied in bytes (if numeric) or
                                                // stride of the block type (if object)
    uint32_t                MaxElements : 16;   // Max allowable index (needed because we don't store object arrays as dependencies,
                                                // and therefore have no way of getting their Element count)

    bool IsObjectAssignment()                   // True for Shader and RObject assignments (the type that appear in pass blocks)
    {
        return IsObjectAssignmentHelper(LhsType);
    }

    SAssignment()
    {
        LhsType = ELHS_Invalid;
        AssignmentType = ERAT_Invalid;

        Destination.pGeneric = nullptr;
        Source.pGeneric = nullptr;

        LastRecomputedTime = 0;
        DependencyCount = 0;
        pDependencies = nullptr;

        DataSize = 0;
    }
};

//////////////////////////////////////////////////////////////////////////
// Private effect heaps
//////////////////////////////////////////////////////////////////////////

// Used to efficiently reallocate data
// 1) For every piece of data that needs reallocation, move it to its new location
// and add an entry into the table
// 2) For everyone that references one of these data blocks, do a quick table lookup
// to find the old pointer and then replace it with the new one
struct SPointerMapping
{
    void *pOld;
    void *pNew;

    static bool AreMappingsEqual(const SPointerMapping &pMap1, const SPointerMapping &pMap2)
    {
        return (pMap1.pOld == pMap2.pOld);
    }

    uint32_t Hash()
    {
        // hash the pointer itself 
        // (using the pointer as a hash would be very bad)
        return ComputeHash((uint8_t*)&pOld, sizeof(pOld));
    }
};

typedef CEffectHashTableWithPrivateHeap<SPointerMapping, SPointerMapping::AreMappingsEqual> CPointerMappingTable;

// Assist adding data to a block of memory
class CEffectHeap
{
protected:
    uint8_t    *m_pData;
    uint32_t    m_dwBufferSize;
    uint32_t    m_dwSize;

    template <bool bCopyData>
    HRESULT AddDataInternal(_In_reads_bytes_(dwSize) const void *pData, _In_ uint32_t dwSize, _Outptr_ void **ppPointer);

public:
    HRESULT ReserveMemory(uint32_t dwSize);
    uint32_t GetSize();
    uint8_t* GetDataStart() { return m_pData; }

    // AddData and AddString append existing data to the buffer - they change m_dwSize. Users are 
    //   not expected to modify the data pointed to by the return pointer
    HRESULT AddString(_In_z_ const char *pString, _Outptr_result_z_ char **ppPointer);
    HRESULT AddData(_In_reads_(dwSize) const void *pData, _In_ uint32_t dwSize, _Outptr_ void **ppPointer);

    // Allocate behaves like a standard new - it will allocate memory, move m_dwSize. The caller is 
    //   expected to use the returned pointer
    void* Allocate(uint32_t dwSize);

    // Move data from the general heap and optional free memory
    HRESULT MoveData(_Inout_updates_bytes_(size) void **ppData, _In_ uint32_t size);
    HRESULT MoveString(_Inout_updates_z_(1)  char **ppStringData);
    HRESULT MoveInterfaceParameters(_In_ uint32_t InterfaceCount, _Inout_updates_(1) SShaderBlock::SInterfaceParameter **ppInterfaces);
    HRESULT MoveEmptyDataBlock(_Inout_updates_(1) void **ppData, _In_ uint32_t size);

    bool IsInHeap(_In_ void *pData) const
    {
        return (pData >= m_pData && pData < (m_pData + m_dwBufferSize));
    }

    CEffectHeap();
    ~CEffectHeap();
};

class CEffectReflection
{
public:
    // Single memory block support
    CEffectHeap m_Heap;
};


class CEffect : public ID3DX11Effect
{
    friend struct SBaseBlock;
    friend struct SPassBlock;
    friend class CEffectLoader;
    friend struct SConstantBuffer;
    friend struct TSamplerVariable<TGlobalVariable<ID3DX11EffectSamplerVariable>>;
    friend struct TSamplerVariable<TVariable<TMember<ID3DX11EffectSamplerVariable>>>;
    
protected:

    uint32_t                m_RefCount;
    uint32_t                m_Flags;

    // Private heap - all pointers should point into here
    CEffectHeap             m_Heap;

    // Reflection object
    CEffectReflection       *m_pReflection;

    // global variables in the effect (aka parameters)
    uint32_t                m_VariableCount;
    SGlobalVariable         *m_pVariables;

    // anonymous shader variables (one for every inline shader assignment)
    uint32_t                m_AnonymousShaderCount;
    SAnonymousShader        *m_pAnonymousShaders;

    // techniques within this effect (the actual data is located in each group)
    uint32_t                m_TechniqueCount;

    // groups within this effect
    uint32_t                m_GroupCount;
    SGroup                  *m_pGroups;
    SGroup                  *m_pNullGroup;

    uint32_t                m_ShaderBlockCount;
    SShaderBlock            *m_pShaderBlocks;

    uint32_t                m_DepthStencilBlockCount;
    SDepthStencilBlock      *m_pDepthStencilBlocks;

    uint32_t                m_BlendBlockCount;
    SBlendBlock             *m_pBlendBlocks;

    uint32_t                m_RasterizerBlockCount;
    SRasterizerBlock        *m_pRasterizerBlocks;

    uint32_t                m_SamplerBlockCount;
    SSamplerBlock           *m_pSamplerBlocks;

    uint32_t                m_MemberDataCount;
    SMemberDataPointer      *m_pMemberDataBlocks;

    uint32_t                m_InterfaceCount;
    SInterface              *m_pInterfaces;

    uint32_t                m_CBCount;
    SConstantBuffer         *m_pCBs;

    uint32_t                m_StringCount;
    SString                 *m_pStrings;

    uint32_t                m_ShaderResourceCount;
    SShaderResource         *m_pShaderResources;

    uint32_t                m_UnorderedAccessViewCount;
    SUnorderedAccessView    *m_pUnorderedAccessViews;

    uint32_t                m_RenderTargetViewCount;
    SRenderTargetView       *m_pRenderTargetViews;

    uint32_t                m_DepthStencilViewCount;
    SDepthStencilView       *m_pDepthStencilViews; 

    Timer                   m_LocalTimer;
    
    // temporary index variable for assignment evaluation
    uint32_t                m_FXLIndex;

    ID3D11Device            *m_pDevice;
    ID3D11DeviceContext     *m_pContext;
    ID3D11ClassLinkage      *m_pClassLinkage;

    // Master lists of reflection interfaces
    CEffectVectorOwner<SSingleElementType> m_pTypeInterfaces;
    CEffectVectorOwner<SMember>            m_pMemberInterfaces;

    //////////////////////////////////////////////////////////////////////////    
    // String & Type pooling

    typedef SType *LPSRUNTIMETYPE;
    static bool AreTypesEqual(const LPSRUNTIMETYPE &pType1, const LPSRUNTIMETYPE &pType2) { return (pType1->IsEqual(pType2)); }
    static bool AreStringsEqual(const LPCSTR &pStr1, const LPCSTR &pStr2) { return strcmp(pStr1, pStr2) == 0; }

    typedef CEffectHashTableWithPrivateHeap<SType *, AreTypesEqual> CTypeHashTable;
    typedef CEffectHashTableWithPrivateHeap<LPCSTR, AreStringsEqual> CStringHashTable;

    // These are used to pool types & type-related strings
    // until Optimize() is called
    CTypeHashTable          *m_pTypePool;
    CStringHashTable        *m_pStringPool;
    CDataBlockStore         *m_pPooledHeap;
    // After Optimize() is called, the type/string pools should be deleted and all
    // remaining data should be migrated into the optimized type heap
    CEffectHeap             *m_pOptimizedTypeHeap;

    // Pools a string or type and modifies the pointer
    void AddStringToPool(const char **ppString);
    void AddTypeToPool(SType **ppType);

    HRESULT OptimizeTypes(_Inout_ CPointerMappingTable *pMappingTable, _In_ bool Cloning = false);


    //////////////////////////////////////////////////////////////////////////    
    // Runtime (performance critical)
    
    void ApplyShaderBlock(_In_ SShaderBlock *pBlock);
    bool ApplyRenderStateBlock(_In_ SBaseBlock *pBlock);
    bool ApplySamplerBlock(_In_ SSamplerBlock *pBlock);
    void ApplyPassBlock(_Inout_ SPassBlock *pBlock);
    bool EvaluateAssignment(_Inout_  SAssignment *pAssignment);
    bool ValidateShaderBlock(_Inout_ SShaderBlock* pBlock );
    bool ValidatePassBlock(_Inout_ SPassBlock* pBlock );
    
    //////////////////////////////////////////////////////////////////////////    
    // Non-runtime functions (not performance critical)    

    SGlobalVariable *FindLocalVariableByName(_In_z_ LPCSTR pVarName);      // Looks in the current effect only
    SGlobalVariable *FindVariableByName(_In_z_ LPCSTR pVarName);
    SVariable *FindVariableByNameWithParsing(_In_z_ LPCSTR pVarName);
    SConstantBuffer *FindCB(_In_z_ LPCSTR pName);
    void ReplaceCBReference(_In_ SConstantBuffer *pOldBufferBlock, _In_ ID3D11Buffer *pNewBuffer); // Used by user-managed CBs
    void ReplaceSamplerReference(_In_ SSamplerBlock *pOldSamplerBlock, _In_ ID3D11SamplerState *pNewSampler);
    void AddRefAllForCloning( _In_ CEffect* pEffectSource );
    HRESULT CopyMemberInterfaces( _In_ CEffect* pEffectSource );
    HRESULT CopyStringPool( _In_ CEffect* pEffectSource, _Inout_ CPointerMappingTable& mappingTable );
    HRESULT CopyTypePool( _In_ CEffect* pEffectSource, _Inout_ CPointerMappingTable& mappingTableTypes, _Inout_ CPointerMappingTable& mappingTableStrings );
    HRESULT CopyOptimizedTypePool( _In_ CEffect* pEffectSource, _Inout_ CPointerMappingTable& mappingTableTypes );
    HRESULT RecreateCBs();
    HRESULT FixupMemberInterface( _Inout_ SMember* pMember, _In_ CEffect* pEffectSource, _Inout_ CPointerMappingTable& mappingTableStrings );

    void ValidateIndex(_In_ uint32_t Elements);

    void IncrementTimer();    
    void HandleLocalTimerRollover();

    friend struct SConstantBuffer;

public:
    CEffect( uint32_t Flags = 0 );
    virtual ~CEffect();
    void ReleaseShaderRefection();

    // Initialize must be called after the effect is created
    HRESULT LoadEffect(_In_reads_bytes_(cbEffectBuffer) const void *pEffectBuffer, _In_ uint32_t cbEffectBuffer);

    // Once the effect is fully loaded, call BindToDevice to attach it to a device
    HRESULT BindToDevice(_In_ ID3D11Device *pDevice, _In_z_ LPCSTR srcName );

    Timer GetCurrentTime() const { return m_LocalTimer; }
    
    bool IsReflectionData(void *pData) const { return m_pReflection->m_Heap.IsInHeap(pData); }
    bool IsRuntimeData(void *pData) const { return m_Heap.IsInHeap(pData); }

    //////////////////////////////////////////////////////////////////////////    
    // Public interface

    // IUnknown
    STDMETHOD(QueryInterface)(REFIID iid, _COM_Outptr_ LPVOID *ppv) override;
    STDMETHOD_(ULONG, AddRef)() override;
    STDMETHOD_(ULONG, Release)() override;

    // ID3DX11Effect
    STDMETHOD_(bool, IsValid)() override { return true; }

    STDMETHOD(GetDevice)(_Outptr_ ID3D11Device** ppDevice) override;    

    STDMETHOD(GetDesc)(_Out_ D3DX11_EFFECT_DESC *pDesc) override;

    STDMETHOD_(ID3DX11EffectConstantBuffer*, GetConstantBufferByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectConstantBuffer*, GetConstantBufferByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3DX11EffectVariable*, GetVariableByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetVariableByName)(_In_z_ LPCSTR Name) override;
    STDMETHOD_(ID3DX11EffectVariable*, GetVariableBySemantic)(_In_z_ LPCSTR Semantic) override;

    STDMETHOD_(ID3DX11EffectTechnique*, GetTechniqueByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectTechnique*, GetTechniqueByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3DX11EffectGroup*, GetGroupByIndex)(_In_ uint32_t Index) override;
    STDMETHOD_(ID3DX11EffectGroup*, GetGroupByName)(_In_z_ LPCSTR Name) override;

    STDMETHOD_(ID3D11ClassLinkage*, GetClassLinkage)() override;

    STDMETHOD(CloneEffect)(_In_ uint32_t Flags, _Outptr_ ID3DX11Effect** ppClonedEffect) override;
    STDMETHOD(Optimize)() override;
    STDMETHOD_(bool, IsOptimized)() override;

    //////////////////////////////////////////////////////////////////////////    
    // New reflection helpers

    ID3DX11EffectType * CreatePooledSingleElementTypeInterface(_In_ SType *pType);
    ID3DX11EffectVariable * CreatePooledVariableMemberInterface(_In_ TTopLevelVariable<ID3DX11EffectVariable> *pTopLevelEntity,
                                                                _In_ const SVariable *pMember,
                                                                _In_ const UDataPointer Data, _In_ bool IsSingleElement, _In_ uint32_t Index);

};

}

#pragma warning(pop)
