//-------------------------------------------------------------------------------------- // 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 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 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 SShaderCBDependency; typedef SShaderDependency SShaderSamplerDependency; typedef SShaderDependency SShaderResourceDependency; typedef SShaderDependency SUnorderedAccessViewDependency; typedef SShaderDependency 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 (( *) 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, 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, 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 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 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>; friend struct TSamplerVariable>>; 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 m_pTypeInterfaces; CEffectVectorOwner 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 CTypeHashTable; typedef CEffectHashTableWithPrivateHeap 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 *pTopLevelEntity, _In_ const SVariable *pMember, _In_ const UDataPointer Data, _In_ bool IsSingleElement, _In_ uint32_t Index); }; } #pragma warning(pop)