// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= D3D11Resources.h: D3D resource RHI definitions. =============================================================================*/ #pragma once #include "BoundShaderStateCache.h" #include "ShaderCore.h" #include "Windows/D3D11ThirdParty.h" class FD3D11DynamicRHI; typedef ID3D11DeviceContext FD3D11DeviceContext; template <> struct TTypeTraits : public TTypeTraitsBase { enum { IsBytewiseComparable = true }; }; /** Convenience typedef: preallocated array of D3D11 input element descriptions. */ typedef TArray > FD3D11VertexElements; /** This represents a vertex declaration that hasn't been combined with a specific shader to create a bound shader. */ class FD3D11VertexDeclaration : public FRHIVertexDeclaration { public: /** Elements of the vertex declaration. */ FD3D11VertexElements VertexElements; uint16 StreamStrides[MaxVertexElementCount]; /** Initialization constructor. */ explicit FD3D11VertexDeclaration(const FD3D11VertexElements& InElements, const uint16* InStrides) : VertexElements(InElements) { FMemory::Memcpy(StreamStrides, InStrides, sizeof(StreamStrides)); } }; struct FD3D11ShaderData { TArray VendorExtensions; bool bShaderNeedsGlobalConstantBuffer; bool bIsSm6Shader; uint16 UAVMask; }; /** This represents a vertex shader that hasn't been combined with a specific declaration to create a bound shader. */ class FD3D11VertexShader : public FRHIVertexShader, public FD3D11ShaderData { public: enum { StaticFrequency = SF_Vertex }; /** The vertex shader resource. */ TRefCountPtr Resource; /** The vertex shader's bytecode, with custom data attached. */ TArray Code; // TEMP remove with removal of bound shader state int32 Offset; }; class FD3D11GeometryShader : public FRHIGeometryShader, public FD3D11ShaderData { public: enum { StaticFrequency = SF_Geometry }; /** The shader resource. */ TRefCountPtr Resource; }; class FD3D11PixelShader : public FRHIPixelShader, public FD3D11ShaderData { public: enum { StaticFrequency = SF_Pixel }; /** The shader resource. */ TRefCountPtr Resource; }; class FD3D11ComputeShader : public FRHIComputeShader, public FD3D11ShaderData { public: enum { StaticFrequency = SF_Compute }; /** The shader resource. */ TRefCountPtr Resource; }; /** * Combined shader state and vertex definition for rendering geometry. * Each unique instance consists of a vertex decl, vertex shader, and pixel shader. */ class FD3D11BoundShaderState : public FRHIBoundShaderState { public: FCachedBoundShaderStateLink CacheLink; uint16 StreamStrides[MaxVertexElementCount]; TRefCountPtr InputLayout; TRefCountPtr VertexShader; TRefCountPtr PixelShader; TRefCountPtr GeometryShader; bool bShaderNeedsGlobalConstantBuffer[SF_NumStandardFrequencies]; /** Initialization constructor. */ FD3D11BoundShaderState( FRHIVertexDeclaration* InVertexDeclarationRHI, FRHIVertexShader* InVertexShaderRHI, FRHIPixelShader* InPixelShaderRHI, FRHIGeometryShader* InGeometryShaderRHI, ID3D11Device* Direct3DDevice ); ~FD3D11BoundShaderState(); /** * Get the shader for the given frequency. */ FORCEINLINE FD3D11VertexShader* GetVertexShader() const { return (FD3D11VertexShader*)CacheLink.GetVertexShader(); } FORCEINLINE FD3D11PixelShader* GetPixelShader() const { return (FD3D11PixelShader*)CacheLink.GetPixelShader(); } FORCEINLINE FD3D11GeometryShader* GetGeometryShader() const { return (FD3D11GeometryShader*)CacheLink.GetGeometryShader(); } }; /** The base class of resources that may be bound as shader resources. */ class FD3D11ViewableResource { public: ~FD3D11ViewableResource() { checkf(!HasLinkedViews(), TEXT("All linked views must have been removed before the underlying resource can be deleted.")); } bool HasLinkedViews() const { return LinkedViews != nullptr; } void UpdateLinkedViews(); private: friend class FD3D11ShaderResourceView; friend class FD3D11UnorderedAccessView; class FD3D11View* LinkedViews = nullptr; }; /** Texture base class. */ class FD3D11Texture final : public FRHITexture, public FD3D11ViewableResource { public: FD3D11Texture(const FRHITextureCreateDesc& InDesc); void FinalizeCreation( ID3D11Resource* InResource, ID3D11ShaderResourceView* InShaderResourceView, int32 InRTVArraySize, bool bInCreatedRTVsPerSlice, TConstArrayView> InRenderTargetViews, TConstArrayView> InDepthStencilViews ); FD3D11Texture( const FRHITextureCreateDesc& InDesc, ID3D11Resource* InResource, ID3D11ShaderResourceView* InShaderResourceView, int32 InRTVArraySize, bool bInCreatedRTVsPerSlice, TConstArrayView> InRenderTargetViews, TConstArrayView> InDepthStencilViews) : FD3D11Texture(InDesc) { FinalizeCreation(InResource, InShaderResourceView, InRTVArraySize, bInCreatedRTVsPerSlice, InRenderTargetViews, InDepthStencilViews); } enum EAliasResourceParam { CreateAlias }; D3D11RHI_API explicit FD3D11Texture(FD3D11Texture const& Other, const FString& Name, EAliasResourceParam); D3D11RHI_API void AliasResource(FD3D11Texture const& Other); D3D11RHI_API virtual ~FD3D11Texture(); inline uint64 GetMemorySize() const { return RHICalcTexturePlatformSize(GetDesc()).Size; } // Accessors. inline ID3D11Resource* GetResource() const { return Resource; } inline ID3D11ShaderResourceView* GetShaderResourceView() const { return ShaderResourceView; } inline bool IsCubemap() const { FRHITextureDesc const& Desc = GetDesc(); return Desc.Dimension == ETextureDimension::TextureCube || Desc.Dimension == ETextureDimension::TextureCubeArray; } inline ID3D11Texture2D* GetD3D11Texture2D() const { check(Resource); check(GetDesc().Dimension == ETextureDimension::Texture2D || GetDesc().Dimension == ETextureDimension::Texture2DArray || GetDesc().Dimension == ETextureDimension::TextureCube || GetDesc().Dimension == ETextureDimension::TextureCubeArray); return static_cast(Resource.GetReference()); } inline ID3D11Texture3D* GetD3D11Texture3D() const { check(Resource); check(GetDesc().Dimension == ETextureDimension::Texture3D); return static_cast(Resource.GetReference()); } inline bool IsTexture3D() const { return GetDesc().Dimension == ETextureDimension::Texture3D; } virtual inline void* GetNativeResource() const override { return GetResource(); } virtual inline void* GetNativeShaderResourceView() const override { return GetShaderResourceView(); } virtual inline void* GetTextureBaseRHI() override { return this; } inline void SetIHVResourceHandle(void* InHandle) { IHVResourceHandle = InHandle; } inline void* GetIHVResourceHandle() const { return IHVResourceHandle; } /** * Get the render target view for the specified mip and array slice. * An array slice of -1 is used to indicate that no array slice should be required. */ inline ID3D11RenderTargetView* GetRenderTargetView(int32 MipIndex, int32 ArraySliceIndex) const { int32 ArrayIndex = MipIndex; if (bCreatedRTVsPerSlice) { check(ArraySliceIndex >= 0); ArrayIndex = MipIndex * RTVArraySize + ArraySliceIndex; } else { // Catch attempts to use a specific slice without having created the texture to support it check(ArraySliceIndex == -1 || ArraySliceIndex == 0); } if ((uint32)ArrayIndex < (uint32)RenderTargetViews.Num()) { return RenderTargetViews[ArrayIndex]; } return 0; } inline ID3D11DepthStencilView* GetDepthStencilView(FExclusiveDepthStencil AccessType) const { return DepthStencilViews[AccessType.GetIndex()]; } #if RHI_ENABLE_RESOURCE_INFO virtual bool GetResourceInfo(FRHIResourceInfo& OutResourceInfo) const override { OutResourceInfo = FRHIResourceInfo{}; OutResourceInfo.Name = GetName(); OutResourceInfo.Type = GetType(); OutResourceInfo.VRamAllocation.AllocationSize = GetMemorySize(); return true; } #endif /** * Locks one of the texture's mip-maps. * @return A pointer to the specified texture data. */ FRHILockTextureResult Lock(FD3D11DynamicRHI* D3DRHI, const FRHILockTextureArgs& Arguments, bool bForceLockDeferred); /** Unlocks a previously locked mip-map. */ void Unlock(FD3D11DynamicRHI* D3DRHI, const FRHILockTextureArgs& Arguments); private: //Resource handle for use by IHVs for SLI and other purposes. void* IHVResourceHandle = nullptr; /** The texture resource. */ TRefCountPtr Resource; /** A shader resource view of the texture. */ TRefCountPtr ShaderResourceView; /** A render targetable view of the texture. */ TArray > RenderTargetViews; /** A depth-stencil targetable view of the texture. */ TRefCountPtr DepthStencilViews[FExclusiveDepthStencil::MaxIndex]; int32 RTVArraySize = 0; uint8 bCreatedRTVsPerSlice : 1; uint8 bAlias : 1; }; class FD3D11RenderQuery { private: TRefCountPtr Resource; // Location the result is written to. uint64* Target = nullptr; // Linked list pointers. Used to build a list of "active" queries, i.e. queries that need data to be polled from the GPU. FD3D11RenderQuery** Prev = nullptr; FD3D11RenderQuery* Next = nullptr; public: uint8 TOPCounter = 0; uint8 BOPCounter = 0; std::atomic LastCachedBOPCounter = 0; enum class EType : uint8 { Timestamp, Occlusion, Profiler } const Type; FD3D11RenderQuery(EType Type); ~FD3D11RenderQuery(); bool CacheResult(class FD3D11DynamicRHI& RHI, bool bWait); void Begin(ID3D11DeviceContext* Context); void End(ID3D11DeviceContext* Context, uint64* Target); bool IsLinked() const { return Prev != nullptr; } private: void Link(); void Unlink(); }; /** D3D11 render query */ class FD3D11RenderQuery_RHI : public FRHIRenderQuery, public FD3D11RenderQuery { public: uint64 Result = 0; FD3D11RenderQuery_RHI(EType Type) : FD3D11RenderQuery(Type) {} }; /** Forward declare the constants ring buffer. */ class FD3D11ConstantsRingBuffer; /** A ring allocation from the constants ring buffer. */ struct FRingAllocation { ID3D11Buffer* Buffer; void* DataPtr; uint32 Offset; uint32 Size; FRingAllocation() : Buffer(NULL) {} inline bool IsValid() const { return Buffer != NULL; } }; /** Uniform buffer resource class. */ class FD3D11UniformBuffer : public FRHIUniformBuffer { public: /** The D3D11 constant buffer resource */ TRefCountPtr Resource; /** Allocation in the constants ring buffer if applicable. */ FRingAllocation RingAllocation; /** Initialization constructor. */ FD3D11UniformBuffer(class FD3D11DynamicRHI* InD3D11RHI, const FRHIUniformBufferLayout* InLayout, ID3D11Buffer* InResource,const FRingAllocation& InRingAllocation, bool bInAllocatedFromPool) : FRHIUniformBuffer(InLayout) , Resource(InResource) , RingAllocation(InRingAllocation) , D3D11RHI(InD3D11RHI) , bAllocatedFromPool(bInAllocatedFromPool) {} virtual ~FD3D11UniformBuffer(); // Provides public non-const access to ResourceTable. // @todo refactor uniform buffers to perform updates as a member function, so this isn't necessary. TArray>& GetResourceTable() { return ResourceTable; } private: class FD3D11DynamicRHI* D3D11RHI; bool bAllocatedFromPool; }; /** Buffer resource class. */ class FD3D11Buffer : public FRHIBuffer, public FD3D11ViewableResource { public: TRefCountPtr Resource; FD3D11Buffer(ID3D11Buffer* InResource, const FRHIBufferCreateDesc& InCreateDesc) : FRHIBuffer(InCreateDesc) , Resource(InResource) {} // FRHIResource overrides #if RHI_ENABLE_RESOURCE_INFO bool GetResourceInfo(FRHIResourceInfo& OutResourceInfo) const override { OutResourceInfo = FRHIResourceInfo{}; OutResourceInfo.Name = GetName(); OutResourceInfo.Type = GetType(); OutResourceInfo.VRamAllocation.AllocationSize = GetSize(); return true; } #endif virtual ~FD3D11Buffer(); void TakeOwnership(FD3D11Buffer& Other); void ReleaseOwnership(); // IRefCountedObject interface. virtual uint32 AddRef() const { return FRHIResource::AddRef(); } virtual uint32 Release() const { return FRHIResource::Release(); } virtual uint32 GetRefCount() const { return FRHIResource::GetRefCount(); } ID3D11Resource* GetResource() const { return Resource.GetReference(); } }; class FD3D11StagingBuffer final : public FRHIStagingBuffer { friend class FD3D11DynamicRHI; public: FD3D11StagingBuffer() : FRHIStagingBuffer() {} ~FD3D11StagingBuffer() override; void* Lock(uint32 Offset, uint32 NumBytes) override; void Unlock() override; uint64 GetGPUSizeBytes() const override { return ShadowBufferSize; } private: FD3D11DeviceContext* Context; TRefCountPtr StagedRead; uint32 ShadowBufferSize; }; class FD3D11GPUFence final : public FRHIGPUFence { private: struct FD3D11Sync { // The graph event to trigger when the sync is resolved. FGraphEventRef Event; // The D3D11 API query object to poll / wait on. TRefCountPtr Query; FD3D11Sync() = default; FD3D11Sync(FGraphEventRef Event, TRefCountPtr Query) : Event(MoveTemp(Event)) , Query(MoveTemp(Query)) {} }; static TQueue ActiveSyncs; static void PollFencesUntil(FGraphEvent* Target); FGraphEventRef Event; public: FD3D11GPUFence(FName InName); void Clear() override; bool Poll() const override; void Wait(FRHICommandListImmediate& RHICmdList, FRHIGPUMask GPUMask) const override; void WriteGPUFence_TopOfPipe(FRHICommandListBase& RHICmdList); static void PollFences() { PollFencesUntil(nullptr); } }; namespace D3D11BufferStats { void UpdateUniformBufferStats(ID3D11Buffer* Buffer, int64 BufferSize, bool bAllocating); void UpdateBufferStats(FD3D11Buffer& Buffer, bool bAllocating); } class FD3D11View : public TIntrusiveLinkedList { public: virtual ~FD3D11View() { Unlink(); } virtual void UpdateView() = 0; }; /** Shader resource view class. */ class FD3D11ShaderResourceView final : public FRHIShaderResourceView, public FD3D11View { public: TRefCountPtr View; FD3D11ShaderResourceView(FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc); FD3D11ViewableResource* GetBaseResource() const; virtual void UpdateView() override; }; /** Unordered access view class. */ class FD3D11UnorderedAccessView final : public FRHIUnorderedAccessView, public FD3D11View { public: TRefCountPtr View; FD3D11UnorderedAccessView(FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc); FD3D11ViewableResource* GetBaseResource() const; virtual void UpdateView() override; }; template struct TD3D11ResourceTraits { }; template<> struct TD3D11ResourceTraits { typedef FD3D11VertexDeclaration TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11VertexShader TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11GeometryShader TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11PixelShader TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11ComputeShader TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11BoundShaderState TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11RenderQuery_RHI TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11UniformBuffer TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11Buffer TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11StagingBuffer TConcreteType; }; // @todo-staging Implement D3D11 fences. template<> struct TD3D11ResourceTraits { typedef FD3D11GPUFence TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11ShaderResourceView TConcreteType; }; template<> struct TD3D11ResourceTraits { typedef FD3D11UnorderedAccessView TConcreteType; };