Files
UnrealEngine/Engine/Source/Runtime/Windows/D3D11RHI/Private/D3D11RHIPrivate.h
2025-05-18 13:04:45 +08:00

1371 lines
52 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
D3D11RHIPrivate.h: Private D3D RHI definitions.
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "ID3D11DynamicRHI.h"
#include "D3D11RHI.h"
// Dependencies.
#include "RHI.h"
#include "GPUProfiler.h"
#include "ShaderCore.h"
#include "Containers/ResourceArray.h"
#include "EngineGlobals.h"
#include "Engine/Engine.h"
#include "HDRHelper.h"
#include "BoundShaderStateHistory.h"
#include "DXGIUtilities.h"
DECLARE_LOG_CATEGORY_EXTERN(LogD3D11RHI, Log, All);
#include "Containers/StaticArray.h"
// D3D RHI public headers.
#include "D3D11Util.h"
#include "D3D11State.h"
#include "D3D11Resources.h"
#include "D3D11Viewport.h"
#include "D3D11ConstantBuffer.h"
#include "D3D11StateCache.h"
#include "D3D11NvidiaAftermath.h"
#include "RHIValidationCommon.h"
#include "RHICoreShader.h"
#ifndef WITH_DX_PERF
#define WITH_DX_PERF 1
#endif
#if INTEL_EXTENSIONS
THIRD_PARTY_INCLUDES_START
#define INTC_IGDEXT_D3D11 1
#include "igdext.h"
THIRD_PARTY_INCLUDES_END
#endif // INTEL_EXTENSIONS
// DX11 doesn't support higher MSAA count
#define DX_MAX_MSAA_COUNT 8
#ifndef WITH_NV_API
#define WITH_NV_API 0
#endif
#ifndef WITH_AMD_AGS
#define WITH_AMD_AGS 0
#endif
/**
* The D3D RHI stats.
*/
DECLARE_CYCLE_STAT_EXTERN(TEXT("Present time"),STAT_D3D11PresentTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("CustomPresent time"), STAT_D3D11CustomPresentTime, STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("CreateTexture time"),STAT_D3D11CreateTextureTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("LockTexture time"),STAT_D3D11LockTextureTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("UnlockTexture time"),STAT_D3D11UnlockTextureTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("CopyTexture time"),STAT_D3D11CopyTextureTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("CreateBoundShaderState time"),STAT_D3D11CreateBoundShaderStateTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("New bound shader state time"),STAT_D3D11NewBoundShaderStateTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("Clean uniform buffer pool"),STAT_D3D11CleanUniformBufferTime,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("Clear shader resources"),STAT_D3D11ClearShaderResourceTime,STATGROUP_D3D11RHI, );
DECLARE_DWORD_ACCUMULATOR_STAT_EXTERN(TEXT("Uniform buffer pool num free"),STAT_D3D11NumFreeUniformBuffers,STATGROUP_D3D11RHI, );
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Immutable Uniform buffers"), STAT_D3D11NumImmutableUniformBuffers, STATGROUP_D3D11RHI, );
DECLARE_DWORD_ACCUMULATOR_STAT_EXTERN(TEXT("Num Bound Shader State"), STAT_D3D11NumBoundShaderState, STATGROUP_D3D11RHI, );
DECLARE_MEMORY_STAT_EXTERN(TEXT("Uniform buffer pool memory"), STAT_D3D11FreeUniformBufferMemory, STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("Update uniform buffer"),STAT_D3D11UpdateUniformBufferTime,STATGROUP_D3D11RHI, );
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Textures Allocated"),STAT_D3D11TexturesAllocated,STATGROUP_D3D11RHI, );
DECLARE_DWORD_COUNTER_STAT_EXTERN(TEXT("Textures Released"),STAT_D3D11TexturesReleased,STATGROUP_D3D11RHI, );
DECLARE_MEMORY_STAT_EXTERN(TEXT("Texture object pool memory"),STAT_D3D11TexturePoolMemory,STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("RenderTargetCommit"), STAT_D3D11RenderTargetCommits, STATGROUP_D3D11RHI, );
DECLARE_CYCLE_STAT_EXTERN(TEXT("RenderTargetCommitUAV"), STAT_D3D11RenderTargetCommitsUAV, STATGROUP_D3D11RHI, );
extern TAutoConsoleVariable<int32> GCVarUseSharedKeyedMutex;
extern TAutoConsoleVariable<int32> GD3D11DebugCvar;
struct FD3D11GlobalStats
{
// in bytes, never change after RHI, needed to scale game features
static int64 GDedicatedVideoMemory;
// in bytes, never change after RHI, needed to scale game features
static int64 GDedicatedSystemMemory;
// in bytes, never change after RHI, needed to scale game features
static int64 GSharedSystemMemory;
// In bytes. Never changed after RHI init. Our estimate of the amount of memory that we can use for graphics resources in total.
static int64 GTotalGraphicsMemory;
};
#if (RHI_NEW_GPU_PROFILER == 0)
// This class has multiple inheritance but really FGPUTiming is a static class
class FD3D11BufferedGPUTiming : public FRenderResource, public FGPUTiming
{
public:
/**
* Constructor.
*
* @param InD3DRHI RHI interface
* @param InBufferSize Number of buffered measurements
*/
FD3D11BufferedGPUTiming(class FD3D11DynamicRHI* InD3DRHI, int32 BufferSize);
/**
* Start a GPU timing measurement.
*/
void StartTiming();
/**
* End a GPU timing measurement.
* The timing for this particular measurement will be resolved at a later time by the GPU.
*/
void EndTiming();
/**
* Retrieves the most recently resolved timing measurement.
* The unit is the same as for FPlatformTime::Cycles(). Returns 0 if there are no resolved measurements.
*
* @return Value of the most recently resolved timing, or 0 if no measurements have been resolved by the GPU yet.
*/
uint64 GetTiming(bool bGetCurrentResultsAndBlock = false);
/**
* Initializes all D3D resources.
*/
virtual void InitRHI(FRHICommandListBase& RHICmdList) override;
/**
* Releases all D3D resources.
*/
virtual void ReleaseRHI() override;
static void CalibrateTimers(FD3D11DynamicRHI* InD3DRHI);
private:
/**
* Initializes the static variables, if necessary.
*/
static void PlatformStaticInitialize(void* UserData);
/** RHI interface */
FD3D11DynamicRHI* D3DRHI;
/** Number of timestamps created in 'StartTimestamps' and 'EndTimestamps'. */
int32 BufferSize;
/** Current timing being measured on the CPU. */
int32 CurrentTimestamp;
/** Number of measurements in the buffers (0 - BufferSize). */
int32 NumIssuedTimestamps;
/** Timestamps for all StartTimings. */
TRefCountPtr<ID3D11Query>* StartTimestamps;
/** Timestamps for all EndTimings. */
TRefCountPtr<ID3D11Query>* EndTimestamps;
/** Whether we are currently timing the GPU: between StartTiming() and EndTiming(). */
bool bIsTiming;
};
/** Used to track whether a period was disjoint on the GPU, which means GPU timings are invalid. */
class FD3D11DisjointTimeStampQuery : public FRenderResource
{
public:
FD3D11DisjointTimeStampQuery(class FD3D11DynamicRHI* InD3DRHI);
void StartTracking();
void EndTracking();
bool IsResultValid();
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT GetResult();
/**
* Initializes all D3D resources.
*/
virtual void InitRHI(FRHICommandListBase& RHICmdList) override;
/**
* Releases all D3D resources.
*/
virtual void ReleaseRHI() override;
private:
TRefCountPtr<ID3D11Query> DisjointQuery;
FD3D11DynamicRHI* D3DRHI;
};
/** A single perf event node, which tracks information about a appBeginDrawEvent/appEndDrawEvent range. */
class FD3D11EventNode : public FGPUProfilerEventNode
{
public:
FD3D11EventNode(const TCHAR* InName, FGPUProfilerEventNode* InParent, class FD3D11DynamicRHI* InRHI) :
FGPUProfilerEventNode(InName, InParent),
Timing(InRHI, 1)
{
// Initialize Buffered timestamp queries
Timing.InitRHI(FRHICommandListExecutor::GetImmediateCommandList()); // can't do this from the RHI thread
}
virtual ~FD3D11EventNode()
{
Timing.ReleaseRHI(); // can't do this from the RHI thread
}
/**
* Returns the time in ms that the GPU spent in this draw event.
* This blocks the CPU if necessary, so can cause hitching.
*/
virtual float GetTiming() override;
virtual void StartTiming() override
{
Timing.StartTiming();
}
virtual void StopTiming() override
{
Timing.EndTiming();
}
FD3D11BufferedGPUTiming Timing;
};
/** An entire frame of perf event nodes, including ancillary timers. */
class FD3D11EventNodeFrame : public FGPUProfilerEventNodeFrame
{
public:
FD3D11EventNodeFrame(class FD3D11DynamicRHI* InRHI) :
FGPUProfilerEventNodeFrame(),
RootEventTiming(InRHI, 1),
DisjointQuery(InRHI)
{
FRHICommandListBase& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
RootEventTiming.InitRHI(RHICmdList);
DisjointQuery.InitRHI(RHICmdList);
}
~FD3D11EventNodeFrame()
{
RootEventTiming.ReleaseRHI();
DisjointQuery.ReleaseRHI();
}
/** Start this frame of per tracking */
virtual void StartFrame() override;
/** End this frame of per tracking, but do not block yet */
virtual void EndFrame() override;
/** Calculates root timing base frequency (if needed by this RHI) */
virtual float GetRootTimingResults() override;
virtual void LogDisjointQuery() override;
/** Timer tracking inclusive time spent in the root nodes. */
FD3D11BufferedGPUTiming RootEventTiming;
/** Disjoint query tracking whether the times reported by DumpEventTree are reliable. */
FD3D11DisjointTimeStampQuery DisjointQuery;
};
/**
* Encapsulates GPU profiling logic and data.
* There's only one global instance of this struct so it should only contain global data, nothing specific to a frame.
*/
struct FD3DGPUProfiler : public FGPUProfiler
{
/** Used to measure GPU time per frame. */
FD3D11BufferedGPUTiming FrameTiming;
class FD3D11DynamicRHI* D3D11RHI;
/** GPU hitch profile histories */
TIndirectArray<FD3D11EventNodeFrame> GPUHitchEventNodeFrames;
FD3DGPUProfiler(class FD3D11DynamicRHI* InD3DRHI);
virtual FGPUProfilerEventNode* CreateEventNode(const TCHAR* InName, FGPUProfilerEventNode* InParent) override
{
FD3D11EventNode* EventNode = new FD3D11EventNode(InName, InParent, D3D11RHI);
return EventNode;
}
virtual void PushEvent(const TCHAR* Name, FColor Color) override;
virtual void PopEvent() override;
void BeginFrame(class FD3D11DynamicRHI* InRHI);
void EndFrame();
};
#endif // (RHI_NEW_GPU_PROFILER == 0)
struct FD3D11TransitionData
{
bool bUAVBarrier;
};
/** Forward declare the context for the AMD AGS utility library. */
struct AGSContext;
struct FD3D11DeviceBasicInfo
{
D3D_FEATURE_LEVEL MaxFeatureLevel;
bool bUMA;
};
struct FD3D11Adapter
{
/** Null if not supported or FindAdapter() wasn't called. */
TRefCountPtr<IDXGIAdapter> DXGIAdapter;
DXGI_ADAPTER_DESC DXGIAdapterDesc;
/** The maximum D3D11 feature level supported. 0 if not supported or FindAdapter() wasn't called */
D3D_FEATURE_LEVEL MaxSupportedFeatureLevel;
/** Whether this is a software adapter */
bool bSoftwareAdapter;
/** Whether the GPU has unified memory. This can be used to identify integrated GPU as well. */
bool bUMA;
// constructors
FD3D11Adapter()
{
}
FD3D11Adapter(TRefCountPtr<IDXGIAdapter> InDXGIAdapter, bool bInSoftwareAdatper, const FD3D11DeviceBasicInfo& DeviceInfo)
: DXGIAdapter(InDXGIAdapter)
, MaxSupportedFeatureLevel(DeviceInfo.MaxFeatureLevel)
, bSoftwareAdapter(bInSoftwareAdatper)
, bUMA(DeviceInfo.bUMA)
{
if (DXGIAdapter.IsValid())
{
VERIFYD3D11RESULT(DXGIAdapter->GetDesc(&DXGIAdapterDesc));
}
}
bool IsValid() const
{
return DXGIAdapter.IsValid();
}
};
PRAGMA_DISABLE_DEPRECATION_WARNINGS
/** The interface which is implemented by the dynamically bound RHI. */
class D3D11RHI_API FD3D11DynamicRHI : public ID3D11DynamicRHI, public IRHICommandContextPSOFallback
{
public:
typedef TMap<FD3D11LockedKey, FD3D11LockedData> FD3D11LockTracker;
friend class FD3D11Viewport;
/** Initialization constructor. */
FD3D11DynamicRHI(IDXGIFactory1* InDXGIFactory1, D3D_FEATURE_LEVEL InFeatureLevel, const FD3D11Adapter& InAdapter);
/** Destructor */
virtual ~FD3D11DynamicRHI();
/** If it hasn't been initialized yet, initializes the D3D device. */
virtual void InitD3DDevice();
// FDynamicRHI interface.
virtual void Init() override;
virtual void Shutdown() override;
virtual const TCHAR* GetName() override { return TEXT("D3D11"); }
virtual void FlushPendingLogs() override;
static FD3D11DynamicRHI& Get() { return *GetDynamicRHI<FD3D11DynamicRHI>(); }
template<typename TRHIType>
static FORCEINLINE typename TD3D11ResourceTraits<TRHIType>::TConcreteType* ResourceCast(TRHIType* Resource)
{
return static_cast<typename TD3D11ResourceTraits<TRHIType>::TConcreteType*>(Resource);
}
static inline FD3D11Texture* ResourceCast(FRHITexture* Texture)
{
if (!Texture)
{
return nullptr;
}
FD3D11Texture* Result = static_cast<FD3D11Texture*>(Texture->GetTextureBaseRHI());
check(Result);
return Result;
}
template<EShaderFrequency ShaderFrequency>
void BindUniformBuffer(uint32 BufferIndex, FRHIUniformBuffer* BufferRHI);
template <typename TRHIShader>
void ApplyStaticUniformBuffers(TRHIShader* Shader);
template<EShaderFrequency ShaderFrequency>
void SetShaderParametersCommon(FD3D11ConstantBuffer* StageConstantBuffer, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters);
template<EShaderFrequency ShaderFrequency>
void SetShaderUnbindsCommon(TConstArrayView<FRHIShaderParameterUnbind> InUnbinds);
/**
* Reads a D3D query's data into the provided buffer.
* @param Query - The D3D query to read data from.
* @param Data - The buffer to read the data into.
* @param DataSize - The size of the buffer.
* @param QueryType e.g. RQT_Occlusion or RQT_AbsoluteTime
* @param bWait - If true, it will wait for the query to finish.
* @param bStallRHIThread - if true, stall RHIT before accessing immediate context
* @return true if the query finished.
*/
bool GetQueryData(ID3D11Query* Query, void* Data, SIZE_T DataSize, bool bTimestamp, bool bWait, bool bStallRHIThread);
virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
virtual FBlendStateRHIRef RHICreateBlendState(const FBlendStateInitializerRHI& Initializer) final override;
virtual FVertexDeclarationRHIRef RHICreateVertexDeclaration(const FVertexDeclarationElementList& Elements) final override;
virtual FPixelShaderRHIRef RHICreatePixelShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FVertexShaderRHIRef RHICreateVertexShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FGeometryShaderRHIRef RHICreateGeometryShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FComputeShaderRHIRef RHICreateComputeShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FStagingBufferRHIRef RHICreateStagingBuffer() final override;
virtual void RHICopyToStagingBuffer(FRHIBuffer* SourceBuffer, FRHIStagingBuffer* DestinationStagingBuffer, uint32 Offset, uint32 NumBytes) final override;
virtual FGPUFenceRHIRef RHICreateGPUFence(const FName& Name) final override;
virtual void RHIWriteGPUFence_TopOfPipe(FRHICommandListBase& RHICmdList, FRHIGPUFence* FenceRHI) final override;
virtual void RHIWriteGPUFence(FRHIGPUFence* Fence) final override;
virtual void* RHILockStagingBuffer(FRHIStagingBuffer* StagingBuffer, FRHIGPUFence* Fence, uint32 Offset, uint32 SizeRHI) final override;
virtual void RHIUnlockStagingBuffer(FRHIStagingBuffer* StagingBuffer) final override;
virtual FBoundShaderStateRHIRef RHICreateBoundShaderState(FRHIVertexDeclaration* VertexDeclaration, FRHIVertexShader* VertexShader, FRHIPixelShader* PixelShader, FRHIGeometryShader* GeometryShader) final override;
virtual FUniformBufferRHIRef RHICreateUniformBuffer(const void* Contents, const FRHIUniformBufferLayout* Layout, EUniformBufferUsage Usage, EUniformBufferValidation Validation) final override;
virtual void RHIUpdateUniformBuffer(FRHICommandListBase& RHICmdList, FRHIUniformBuffer* UniformBufferRHI, const void* Contents) final override;
#if ENABLE_LOW_LEVEL_MEM_TRACKER || UE_MEMORY_TRACE_ENABLED
virtual void RHIUpdateAllocationTags(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer) final override;
#endif
[[nodiscard]] FD3D11Buffer* BeginCreateBufferInternal(const FRHIBufferCreateDesc& CreateDesc);
[[nodiscard]] void FinalizeCreateBufferInternal(FD3D11Buffer* Buffer, TConstArrayView<uint8> InitialData);
[[nodiscard]] FD3D11Buffer* CreateBufferInternal(const FRHIBufferCreateDesc& CreateDesc, TConstArrayView<uint8> InitialData);
[[nodiscard]] virtual FRHIBufferInitializer RHICreateBufferInitializer(FRHICommandListBase& RHICmdList, const FRHIBufferCreateDesc& CreateDesc) final override;
virtual void RHIReplaceResources(FRHICommandListBase& RHICmdList, TArray<FRHIResourceReplaceInfo>&& ReplaceInfos) final override;
virtual void* LockBuffer_BottomOfPipe(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, uint32 Offset, uint32 Size, EResourceLockMode LockMode) final override;
virtual void UnlockBuffer_BottomOfPipe(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer) final override;
virtual FRHICalcTextureSizeResult RHICalcTexturePlatformSize(FRHITextureDesc const& Desc, uint32 FirstMipIndex) final override;
virtual void RHIGetTextureMemoryStats(FTextureMemoryStats& OutStats) final override;
virtual bool RHIGetTextureMemoryVisualizeData(FColor* TextureData,int32 SizeX,int32 SizeY,int32 Pitch,int32 PixelSize) final override;
[[nodiscard]] FD3D11Texture* BeginCreateTextureInternal(const FRHITextureCreateDesc& CreateDesc);
void FinalizeCreateTexture2DInternal(FD3D11Texture* Texture, TConstArrayView<D3D11_SUBRESOURCE_DATA> InitialData);
void FinalizeCreateTexture3DInternal(FD3D11Texture* Texture, TConstArrayView<D3D11_SUBRESOURCE_DATA> InitialData);
FD3D11Texture* FinalizeCreateTextureInternal(FD3D11Texture* Texture, const FRHITextureDesc& InDesc, TConstArrayView<uint8> InitialData);
[[nodiscard]] FD3D11Texture* CreateTextureInternal(const FRHITextureCreateDesc& CreateDesc, TConstArrayView<uint8> InitialData);
[[nodiscard]] virtual FRHITextureInitializer RHICreateTextureInitializer(FRHICommandListBase& RHICmdList, const FRHITextureCreateDesc& CreateDesc) final override;
virtual FTextureRHIRef RHIAsyncCreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags Flags, ERHIAccess InResourceState, void** InitialMipData, uint32 NumInitialMips, const TCHAR* DebugName, FGraphEventRef& OutCompletionEvent) final override;
virtual uint32 RHIComputeMemorySize(FRHITexture* TextureRHI) final override;
virtual void RHIAsyncCopyTexture2DCopy(FRHITexture* NewTexture2DRHI, FRHITexture* Texture2DRHI, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus);
virtual FTextureRHIRef RHIAsyncReallocateTexture2D(FRHITexture* Texture2D, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus) final override;
virtual FRHILockTextureResult RHILockTexture(FRHICommandListImmediate& RHICmdList, const FRHILockTextureArgs& Arguments) final override;
virtual void RHIUnlockTexture(FRHICommandListImmediate& RHICmdList, const FRHILockTextureArgs& Arguments) final override;
virtual void RHIUpdateTexture2D(FRHICommandListBase& RHICmdList, FRHITexture* Texture, uint32 MipIndex, const struct FUpdateTextureRegion2D& UpdateRegion, uint32 SourcePitch, const uint8* SourceData) final override;
virtual void RHIUpdateTexture3D(FRHICommandListBase& RHICmdList, FRHITexture* Texture, uint32 MipIndex, const struct FUpdateTextureRegion3D& UpdateRegion, uint32 SourceRowPitch, uint32 SourceDepthPitch, const uint8* SourceData) final override;
virtual void RHIBindDebugLabelName(FRHICommandListBase& RHICmdList, FRHITexture* Texture, const TCHAR* Name) final override;
virtual void RHIBindDebugLabelName(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, const TCHAR* Name) final override;
virtual void RHIBindDebugLabelName(FRHICommandListBase& RHICmdList, FRHIUnorderedAccessView* UnorderedAccessViewRHI, const TCHAR* Name) final override;
virtual void RHIReadSurfaceData(FRHITexture* Texture,FIntRect Rect,TArray<FColor>& OutData,FReadSurfaceDataFlags InFlags) final override;
virtual void RHIReadSurfaceData(FRHITexture* TextureRHI, FIntRect InRect, TArray<FLinearColor>& OutData, FReadSurfaceDataFlags InFlags) final override;
virtual void RHIMapStagingSurface(FRHITexture* Texture, FRHIGPUFence* Fence, void*& OutData, int32& OutWidth, int32& OutHeight, uint32 GPUIndex = 0) final override;
virtual void RHIUnmapStagingSurface(FRHITexture* Texture, uint32 GPUIndex = 0) final override;
virtual void RHIReadSurfaceFloatData(FRHITexture* Texture,FIntRect Rect,TArray<FFloat16Color>& OutData,ECubeFace CubeFace,int32 ArrayIndex,int32 MipIndex) final override;
virtual void RHIRead3DSurfaceFloatData(FRHITexture* Texture,FIntRect Rect,FIntPoint ZMinMax,TArray<FFloat16Color>& OutData) final override;
virtual FRenderQueryRHIRef RHICreateRenderQuery(ERenderQueryType QueryType) final override;
virtual bool RHIGetRenderQueryResult(FRHIRenderQuery* RenderQuery, uint64& OutResult, bool bWait, uint32 GPUIndex = INDEX_NONE) final override;
virtual FTextureRHIRef RHIGetViewportBackBuffer(FRHIViewport* Viewport) final override;
virtual void RHIAliasTextureResources(FTextureRHIRef& DestTexture, FTextureRHIRef& SrcTexture) final override;
virtual FTextureRHIRef RHICreateAliasedTexture(FTextureRHIRef& SourceTexture) final override;
virtual void RHIAdvanceFrameForGetViewportBackBuffer(FRHIViewport* Viewport) final override;
virtual void RHIFlushResources() final override;
virtual FViewportRHIRef RHICreateViewport(void* WindowHandle, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, EPixelFormat PreferredPixelFormat) override;
virtual void RHIResizeViewport(FRHIViewport* Viewport, uint32 SizeX, uint32 SizeY, bool bIsFullscreen) final override;
virtual void RHIResizeViewport(FRHIViewport* Viewport, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, EPixelFormat PreferredPixelFormat) final override;
virtual void RHIHandleDisplayChange() final override;
virtual void RHITick(float DeltaTime) final override;
virtual void RHIBlockUntilGPUIdle() final override;
virtual bool RHIGetAvailableResolutions(FScreenResolutionArray& Resolutions, bool bIgnoreRefreshRate) final override;
virtual void RHIGetSupportedResolution(uint32& Width, uint32& Height) final override;
virtual void* RHIGetNativeDevice() final override;
virtual void* RHIGetNativeInstance() final override;
virtual void* RHIGetNativeCommandBuffer() final override;
virtual class IRHICommandContext* RHIGetDefaultContext() final override;
virtual IRHIComputeContext* RHIGetCommandContext(ERHIPipeline Pipeline, FRHIGPUMask GPUMask) final override;
virtual void RHIFinalizeContext(FRHIFinalizeContextArgs&& Args, TRHIPipelineArray<IRHIPlatformCommandList*>& Output) final override;
virtual void RHISubmitCommandLists(FRHISubmitCommandListsArgs&& Args) final override;
// SRV / UAV creation functions
virtual FShaderResourceViewRHIRef RHICreateShaderResourceView (class FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc) final override;
virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(class FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc) final override;
virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) final override;
virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
virtual void RHIDispatchIndirectComputeShader(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHIBeginUAVOverlap() final override;
virtual void RHIEndUAVOverlap() final override;
virtual void RHISetMultipleViewports(uint32 Count, const FViewportBounds* Data) final override;
virtual void RHIClearUAVFloat(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FVector4f& Values) final override;
virtual void RHIClearUAVUint(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FUintVector4& Values) final override;
virtual void RHICopyTexture(FRHITexture* SourceTexture, FRHITexture* DestTexture, const FRHICopyTextureInfo& CopyInfo) final override;
virtual void RHICopyBufferRegion(FRHIBuffer* DestBuffer, uint64 DstOffset, FRHIBuffer* SourceBuffer, uint64 SrcOffset, uint64 NumBytes) final override;
virtual void RHICreateTransition(FRHITransition* Transition, const FRHITransitionCreateInfo& CreateInfo) final override;
virtual void RHIReleaseTransition(FRHITransition* Transition) final override;
virtual void RHIBeginTransitions(TArrayView<const FRHITransition*> Transitions) override final;
virtual void RHIEndTransitions(TArrayView<const FRHITransition*> Transitions) override final;
virtual void RHIEndRenderQuery_TopOfPipe (FRHICommandListBase& RHICmdList, FRHIRenderQuery* RenderQuery) override final;
virtual void RHIBeginRenderQuery(FRHIRenderQuery* RenderQuery) final override;
virtual void RHIEndRenderQuery (FRHIRenderQuery* RenderQuery) final override;
virtual void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) final override;
virtual void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) final override;
virtual void RHIEndFrame(const FRHIEndFrameArgs& Args) final override;
virtual void RHISetStreamSource(uint32 StreamIndex, FRHIBuffer* VertexBuffer, uint32 Offset) final override;
virtual void RHISetRasterizerState(FRHIRasterizerState* NewState) final override;
virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) final override;
virtual void RHISetStereoViewport(float LeftMinX, float RightMinX, float LeftMinY, float RightMinY, float MinZ, float LeftMaxX, float RightMaxX, float LeftMaxY, float RightMaxY, float MaxZ) override;
virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) final override;
virtual void RHISetBoundShaderState(FRHIBoundShaderState* BoundShaderState) final override;
virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsState, uint32 StencilRef, bool bApplyAdditionalState) final override;
virtual void RHISetStaticUniformBuffers(const FUniformBufferStaticBindings& InUniformBuffers) final override;
virtual void RHISetStaticUniformBuffer(FUniformBufferStaticSlot Slot, FRHIUniformBuffer* Buffer) final override;
virtual void RHISetShaderParameters(FRHIComputeShader* Shader, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters, TConstArrayView<FRHIShaderParameterResource> InBindlessParameters) final override;
virtual void RHISetShaderParameters(FRHIGraphicsShader* Shader, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters, TConstArrayView<FRHIShaderParameterResource> InBindlessParameters) final override;
virtual void RHISetShaderUnbinds(FRHIComputeShader* Shader, TConstArrayView<FRHIShaderParameterUnbind> InUnbinds) final override;
virtual void RHISetShaderUnbinds(FRHIGraphicsShader* Shader, TConstArrayView<FRHIShaderParameterUnbind> InUnbinds) final override;
virtual void RHISetDepthStencilState(FRHIDepthStencilState* NewState, uint32 StencilRef) final override;
virtual void RHISetStencilRef(uint32 StencilRef) final override;
virtual void RHISetBlendState(FRHIBlendState* NewState, const FLinearColor& BlendFactor) final override;
virtual void RHISetBlendFactor(const FLinearColor& BlendFactor) final override;
void SetRenderTargets(uint32 NumSimultaneousRenderTargets, const FRHIRenderTargetView* NewRenderTargets, const FRHIDepthRenderTargetView* NewDepthStencilTarget);
void InternalSetUAVCS(uint32 BindIndex, FD3D11UnorderedAccessView* UnorderedAccessViewRHI);
void InternalSetUAVVSPS(uint32 BindIndex, FD3D11UnorderedAccessView* UnorderedAccessViewRHI);
void SetRenderTargetsAndClear(const FRHISetRenderTargetsInfo& RenderTargetsInfo);
virtual void RHIDrawPrimitive(uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances) final override;
virtual void RHIDrawPrimitiveIndirect(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHIDrawIndexedIndirect(FRHIBuffer* IndexBufferRHI, FRHIBuffer* ArgumentsBufferRHI, int32 DrawArgumentsIndex, uint32 NumInstances) final override;
virtual void RHIDrawIndexedPrimitive(FRHIBuffer* IndexBuffer, int32 BaseVertexIndex, uint32 FirstInstance, uint32 NumVertices, uint32 StartIndex, uint32 NumPrimitives, uint32 NumInstances) final override;
virtual void RHIDrawIndexedPrimitiveIndirect(FRHIBuffer* IndexBuffer, FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHIEnableDepthBoundsTest(bool bEnable) final override
{
if (GSupportsDepthBoundsTest && StateCache.bDepthBoundsEnabled != bEnable)
{
EnableDepthBoundsTest(bEnable, 0.0f, 1.0f);
}
}
virtual void RHISetDepthBounds(float MinDepth, float MaxDepth) final override
{
if (GSupportsDepthBoundsTest && (StateCache.DepthBoundsMin != MinDepth || StateCache.DepthBoundsMax != MaxDepth))
{
EnableDepthBoundsTest(true, MinDepth, MaxDepth);
}
}
#if WITH_RHI_BREADCRUMBS
virtual void RHIBeginBreadcrumbGPU(FRHIBreadcrumbNode* Breadcrumb) final override;
virtual void RHIEndBreadcrumbGPU (FRHIBreadcrumbNode* Breadcrumb) final override;
#endif
void PollQueryResults();
// *_RenderThread functions. Command lists call these functions on RT. You can implement your own behavior inside these functions.
// For example, deferring the actual creation to RHI thread by sending an RHI command.
// For D3D11, these functions mainly just remove RHIT stalls because ID3D11Device is thread safe.
virtual FTextureRHIRef AsyncReallocateTexture2D_RenderThread(class FRHICommandListImmediate& RHICmdList, FRHITexture* Texture2D, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus) final override;
virtual void RHIEndUpdateTexture3D(FRHICommandListBase& RHICmdList, FUpdateTexture3DData& UpdateData) final override;
virtual void RHIBeginRenderPass(const FRHIRenderPassInfo& InInfo, const TCHAR* InName) final override;
virtual void RHIEndRenderPass() final override;
void ResolveTexture(UE::RHICore::FResolveTextureInfo Info);
// ID3D11DynamicRHI interface
virtual ID3D11Device* RHIGetDevice() const final override;
virtual ID3D11DeviceContext* RHIGetDeviceContext() const final override;
virtual IDXGIAdapter* RHIGetAdapter() const final override;
virtual IDXGISwapChain* RHIGetSwapChain(FRHIViewport* InViewport) const final override;
virtual DXGI_FORMAT RHIGetSwapChainFormat(EPixelFormat InFormat) const final override;
virtual FTextureRHIRef RHICreateTexture2DFromResource(EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D11Texture2D* Resource) final override;
virtual FTextureRHIRef RHICreateTexture2DArrayFromResource(EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding&, ID3D11Texture2D* Resource) final override;
virtual FTextureRHIRef RHICreateTextureCubeFromResource(EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D11Texture2D* Resource) final override;
virtual ID3D11Buffer* RHIGetResource(FRHIBuffer* InBuffer) const final override;
virtual ID3D11Resource* RHIGetResource(FRHITexture* InTexture) const final override;
virtual int64 RHIGetResourceMemorySize(FRHITexture* InTexture) const final override;
virtual ID3D11RenderTargetView* RHIGetRenderTargetView(FRHITexture* InTexture, int32 InMipIndex = 0, int32 InArraySliceIndex = -1) const final override;
virtual ID3D11ShaderResourceView* RHIGetShaderResourceView(FRHITexture* InTexture) const final override;
virtual void RHIRegisterWork(uint32 NumPrimitives) final override;
virtual void RHIVerifyResult(ID3D11Device* Device, HRESULT Result, const ANSICHAR* Code, const ANSICHAR* Filename, uint32 Line) const final override;
virtual void RHIGetDisplaysInformation(FDisplayInformationArray& OutDisplayInformation) final override;
// Accessors.
ID3D11Device* GetDevice() const
{
return Direct3DDevice;
}
FD3D11DeviceContext* GetDeviceContext() const
{
return Direct3DDeviceIMContext;
}
IDXGIFactory1* GetFactory() const
{
return DXGIFactory1;
}
void AddLockedData(const FD3D11LockedKey& Key, const FD3D11LockedData& LockedData)
{
FScopeLock Lock(&LockTrackerCS);
LockTracker.Add(Key, LockedData);
}
bool RemoveLockedData(const FD3D11LockedKey& Key, FD3D11LockedData& OutLockedData)
{
FScopeLock Lock(&LockTrackerCS);
return LockTracker.RemoveAndCopyValue(Key, OutLockedData);
}
bool IsQuadBufferStereoEnabled();
void DisableQuadBufferStereo();
void BeginRecursiveCommand()
{
// Nothing to do
}
private:
void EnableDepthBoundsTest(bool bEnable, float MinDepth, float MaxDepth);
static void ClearUAV(TRHICommandList_RecursiveHazardous<FD3D11DynamicRHI>& RHICmdList, FD3D11UnorderedAccessView* UAV, const void* ClearValues, bool bFloat);
enum class EForceFullScreenClear
{
EDoNotForce,
EForce
};
virtual void RHIClearMRTImpl(const bool* bClearColorArray, int32 NumClearColors, const FLinearColor* ColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil);
template <EShaderFrequency ShaderFrequency>
void ClearShaderResourceViews(FD3D11ViewableResource* Resource);
template <EShaderFrequency ShaderFrequency>
void ClearAllShaderResourcesForFrequency();
template <EShaderFrequency ShaderFrequency>
void InternalSetShaderResourceView(FD3D11ViewableResource* Resource, ID3D11ShaderResourceView* SRV, int32 ResourceIndex);
void TrackResourceBoundAsVB(FD3D11ViewableResource* Resource, int32 StreamIndex);
void TrackResourceBoundAsIB(FD3D11ViewableResource* Resource);
void SetCurrentComputeShader(FRHIComputeShader* ComputeShader)
{
CurrentComputeShader = ComputeShader;
}
const FComputeShaderRHIRef& GetCurrentComputeShader() const
{
return CurrentComputeShader;
}
public:
template <EShaderFrequency ShaderFrequency>
void SetShaderResourceView(FD3D11ViewableResource* Resource, ID3D11ShaderResourceView* SRV, int32 ResourceIndex)
{
InternalSetShaderResourceView<ShaderFrequency>(Resource, SRV, ResourceIndex);
}
void ClearState();
void ConditionalClearShaderResource(FD3D11ViewableResource* Resource, bool bCheckBoundInputAssembler);
void ClearAllShaderResources();
EPixelFormat GetDisplayFormat(EPixelFormat InPixelFormat) const;
FD3D11StateCache& GetStateCache() { return StateCache; }
protected:
/** The global D3D interface. */
TRefCountPtr<IDXGIFactory1> DXGIFactory1;
#if PLATFORM_WINDOWS
TRefCountPtr<IDXGIFactory1> DXGIFactoryForDisplayList;
#endif
// Whether HDR is available from the particular DXGI factories available
bool bDXGISupportsHDR;
/** The global D3D device's immediate context */
TRefCountPtr<FD3D11DeviceContext> Direct3DDeviceIMContext;
#if WITH_DX_PERF
TRefCountPtr<ID3DUserDefinedAnnotation> Direct3DDeviceIMAnnotation;
#endif
#if NV_AFTERMATH
UE::RHICore::Nvidia::Aftermath::D3D11::FCommandList AftermathHandle = nullptr;
#endif
/** The global D3D device's immediate context */
TRefCountPtr<FD3D11Device> Direct3DDevice;
FD3D11StateCache StateCache;
/** Tracks outstanding locks on each thread */
FD3D11LockTracker LockTracker;
FCriticalSection LockTrackerCS;
/** A list of all viewport RHIs that have been created. */
TArray<FD3D11Viewport*> Viewports;
/** The viewport which is currently being drawn. */
TRefCountPtr<FD3D11Viewport> DrawingViewport;
/** The feature level of the device. */
D3D_FEATURE_LEVEL FeatureLevel;
/**
* The context for the AMD AGS utility library.
* AGSContext does not implement AddRef/Release.
* Just use a bare pointer.
*/
AGSContext* AmdAgsContext;
#if INTEL_EXTENSIONS
// Context and functions for Intel extension framework utility library
INTCExtensionContext* IntelExtensionContext;
bool bIntelSupportsUAVOverlap;
#endif // INTEL_EXTENSIONS
// set by UpdateMSAASettings(), get by GetMSAAQuality()
// [SampleCount] = Quality, 0xffffffff if not supported
uint32 AvailableMSAAQualities[DX_MAX_MSAA_COUNT + 1];
/** A buffer in system memory containing all zeroes of the specified size. */
void* ZeroBuffer;
uint32 ZeroBufferSize;
// Tracks the currently set state blocks.
bool bCurrentDepthStencilStateIsReadOnly;
// Current PSO Primitive Type
EPrimitiveType PrimitiveType;
TRefCountPtr<ID3D11RenderTargetView> CurrentRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
TRefCountPtr<FD3D11UnorderedAccessView> CurrentUAVs[D3D11_PS_CS_UAV_REGISTER_COUNT];
ID3D11UnorderedAccessView* UAVBound[D3D11_PS_CS_UAV_REGISTER_COUNT];
uint32 UAVBindFirst;
uint32 UAVBindCount;
uint32 UAVSChanged;
uint32 CurrentRTVOverlapMask;
uint32 CurrentUAVMask;
TRefCountPtr<ID3D11DepthStencilView> CurrentDepthStencilTarget;
TRefCountPtr<FD3D11Texture> CurrentDepthTexture;
FD3D11ViewableResource* CurrentResourcesBoundAsSRVs[SF_NumStandardFrequencies][D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
FD3D11ViewableResource* CurrentResourcesBoundAsVBs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
FD3D11ViewableResource* CurrentResourceBoundAsIB;
int32 MaxBoundShaderResourcesIndex[SF_NumStandardFrequencies];
int32 MaxBoundVertexBufferIndex;
uint32 NumSimultaneousRenderTargets;
uint32 NumUAVs;
/** Internal frame counter that just counts calls to Present */
uint32 PresentCounter;
// Render queries that should be polled by the RHI thread.
struct
{
FD3D11RenderQuery* First = nullptr;
FD3D11RenderQuery* Last = nullptr;
} ActiveQueries;
friend class FD3D11RenderQuery;
struct FProfiler
{
struct FFrame
{
TRefCountPtr<ID3D11Query> CompletionQuery;
#if RHI_NEW_GPU_PROFILER
UE::RHI::GPUProfiler::FEventStream EventStream;
#endif
#if WITH_RHI_BREADCRUMBS
FRHIBreadcrumbAllocatorArray BreadcrumbAllocators{};
#endif
FFrame()
#if RHI_NEW_GPU_PROFILER
: EventStream(UE::RHI::GPUProfiler::FQueue(UE::RHI::GPUProfiler::FQueue::EType::Graphics, 0, 0))
#endif
{}
};
FFrame Current;
TQueue<TUniquePtr<FFrame>> Pending;
TArray<FD3D11RenderQuery*> TimestampPool;
TArray<TRefCountPtr<ID3D11Query>> EventPool;
} Profiler;
#if RHI_NEW_GPU_PROFILER
template <typename TEventType, typename... TArgs>
TEventType& EmplaceProfilerEvent(TArgs&&... Args)
{
return Profiler.Current.EventStream.Emplace<TEventType>(Forward<TArgs>(Args)...);
}
void InsertProfilerTimestamp(uint64* Target);
void FlushProfilerStats()
{
// Flush accumulated draw stats
if (StatEvent)
{
EmplaceProfilerEvent<UE::RHI::GPUProfiler::FEvent::FStats>() = StatEvent;
StatEvent = {};
}
}
#endif // RHI_NEW_GPU_PROFILER
public:
struct FTimestampCalibration
{
uint64 CPUTimestamp = 0;
uint64 CPUFrequency = 0;
uint64 GPUTimestamp = 0;
uint64 GPUFrequency = 0;
};
TOptional<FTimestampCalibration> CalibrateTimers();
protected:
TOptional<FTimestampCalibration> TimestampCalibration;
/** D3D11 defines a maximum of 14 constant buffers per shader stage. */
enum { MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE = 14 };
/** Track the currently bound uniform buffers. */
FRHIUniformBuffer* BoundUniformBuffers[SF_NumStandardFrequencies][MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE];
/** Bit array to track which uniform buffers have changed since the last draw call. */
uint16 DirtyUniformBuffers[SF_NumStandardFrequencies];
TArray<FRHIUniformBuffer*> StaticUniformBuffers;
/** Tracks the current depth stencil access type. */
FExclusiveDepthStencil CurrentDSVAccessType;
/** When a new shader is set, we discard all old constants set for the previous shader. */
bool bDiscardSharedConstants;
/** A list of all D3D constant buffers RHIs that have been created. */
TRefCountPtr<FD3D11ConstantBuffer> VSConstantBuffer;
TRefCountPtr<FD3D11ConstantBuffer> PSConstantBuffer;
TRefCountPtr<FD3D11ConstantBuffer> GSConstantBuffer;
TRefCountPtr<FD3D11ConstantBuffer> CSConstantBuffer;
/** A history of the most recently used bound shader states, used to keep transient bound shader states from being recreated for each use. */
TGlobalResource< TBoundShaderStateHistory<10000> > BoundShaderStateHistory;
FComputeShaderRHIRef CurrentComputeShader;
FDisplayInformationArray DisplayList;
HANDLE ExceptionHandlerHandle = INVALID_HANDLE_VALUE;
bool bRenderDoc = false;
public:
#if (RHI_NEW_GPU_PROFILER == 0)
void RegisterGPUWork(uint32 NumPrimitives = 0, uint32 NumVertices = 0) { GPUProfilingData.RegisterGPUWork(NumPrimitives, NumVertices); }
void RegisterGPUDispatch(FIntVector GroupCount) { GPUProfilingData.RegisterGPUDispatch(GroupCount); }
#endif
inline const FD3D11Adapter& GetAdapter() const { return Adapter; }
protected:
#if (RHI_NEW_GPU_PROFILER == 0)
FD3DGPUProfiler GPUProfilingData;
#endif
FD3D11Adapter Adapter;
FD3D11Texture* CreateTextureFromResource(bool bTextureArray, bool bCubeTexture, EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D11Texture2D* TextureResource);
/** Initializes the constant buffers. Called once at RHI initialization time. */
void InitConstantBuffers();
/** needs to be called before each draw call */
virtual void CommitNonComputeShaderConstants();
/** needs to be called before each dispatch call */
virtual void CommitComputeShaderConstants();
template <class ShaderType> void SetResourcesFromTables(const ShaderType* RESTRICT);
void CommitGraphicsResourceTables();
void CommitComputeResourceTables(FD3D11ComputeShader* ComputeShader);
void ValidateExclusiveDepthStencilAccess(FExclusiveDepthStencil Src) const;
/**
* Gets the best supported MSAA settings from the provided MSAA count to check against.
*
* @param PlatformFormat The format of the texture being created
* @param MSAACount The MSAA count to check against.
* @param OutBestMSAACount The best MSAA count that is suppored. Could be smaller than MSAACount if it is not supported
* @param OutMSAAQualityLevels The number MSAA quality levels for the best msaa count supported
*/
void GetBestSupportedMSAASetting( DXGI_FORMAT PlatformFormat, uint32 MSAACount, uint32& OutBestMSAACount, uint32& OutMSAAQualityLevels );
// shared code for different D3D11 devices (e.g. PC DirectX11 and XboxOne) called
// after device creation and GRHISupportsAsyncTextureCreation was set and before resource init
void SetupAfterDeviceCreation();
// called by SetupAfterDeviceCreation() when the device gets initialized
void UpdateMSAASettings();
// @return 0xffffffff if not not supported
uint32 GetMaxMSAAQuality(uint32 SampleCount);
void CommitRenderTargetsAndUAVs();
void CommitRenderTargets(bool bClearUAVS);
void CommitUAVs();
/**
* Cleanup the D3D device.
* This function must be called from the main game thread.
*/
virtual void CleanupD3DDevice();
void ReleasePooledUniformBuffers();
template<typename TPixelShader>
static void ResolveTextureUsingShader(
FD3D11DynamicRHI* const This,
FD3D11Texture* const SourceTexture,
FD3D11Texture* const DestTexture,
ID3D11RenderTargetView* const DestTextureRTV,
ID3D11DepthStencilView* const DestTextureDSV,
D3D11_TEXTURE2D_DESC const& ResolveTargetDesc,
FResolveRect const& SourceRect,
FResolveRect const& DestRect,
typename TPixelShader::FParameter const PixelShaderParameter
);
/**
* Returns a pointer to a texture resource that can be used for CPU reads.
* Note: the returned resource could be the original texture or a new temporary texture.
* @param TextureRHI - Source texture to create a staging texture from.
* @param InRect - rectangle to 'stage'.
* @param StagingRectOUT - parameter is filled with the rectangle to read from the returned texture.
* @return The CPU readable Texture object.
*/
TRefCountPtr<ID3D11Texture2D> GetStagingTexture(FRHITexture* TextureRHI,FIntRect InRect, FIntRect& OutRect, FReadSurfaceDataFlags InFlags);
void ReadSurfaceDataNoMSAARaw(FRHITexture* TextureRHI,FIntRect Rect,TArray<uint8>& OutData, FReadSurfaceDataFlags InFlags);
void ReadSurfaceDataMSAARaw(FRHITexture* TextureRHI, FIntRect Rect, TArray<uint8>& OutData, FReadSurfaceDataFlags InFlags);
#if INTEL_EXTENSIONS
void StartIntelExtensions();
void StopIntelExtensions();
#endif // INTEL_EXTENSIONS
bool bUAVOverlapEnabled = false;
void EnableUAVOverlap();
void DisableUAVOverlap();
bool SetupDisplayHDRMetaData();
void UpdateMemoryStats();
friend struct FD3DGPUProfiler;
};
PRAGMA_ENABLE_DEPRECATION_WARNINGS
/** Implements the D3D11RHI module as a dynamic RHI providing module. */
class FD3D11DynamicRHIModule : public IDynamicRHIModule
{
public:
// IModuleInterface
virtual bool SupportsDynamicReloading() override { return false; }
// IDynamicRHIModule
virtual bool IsSupported() override;
virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override;
private:
FD3D11Adapter ChosenAdapter;
// set MaxSupportedFeatureLevel and ChosenAdapter
void FindAdapter();
};
// 1d, 31 bit (uses the sign bit for internal use), O(n) where n is the amount of elements stored
// does not enforce any alignment
// unoccupied regions get compacted but occupied don't get compacted
class FRangeAllocator
{
public:
struct FRange
{
// not valid
FRange()
: Start(0)
, Size(0)
{
check(!IsValid());
}
void SetOccupied(int32 InStart, int32 InSize)
{
check(InStart >= 0);
check(InSize > 0);
Start = InStart;
Size = InSize;
check(IsOccupied());
}
void SetUnOccupied(int32 InStart, int32 InSize)
{
check(InStart >= 0);
check(InSize > 0);
Start = InStart;
Size = -InSize;
check(!IsOccupied());
}
bool IsValid() { return Size != 0; }
bool IsOccupied() const { return Size > 0; }
uint32 ComputeSize() const { return (Size > 0) ? Size : -Size; }
// @apram InSize can be <0 to remove from the size
void ExtendUnoccupied(int32 InSize) { check(!IsOccupied()); Size -= InSize; }
void MakeOccupied(int32 InSize) { check(InSize > 0); check(!IsOccupied()); Size = InSize; }
void MakeUnOccupied() { check(IsOccupied()); Size = -Size; }
bool operator==(const FRange& rhs) const { return Start == rhs.Start && Size == rhs.Size; }
int32 GetStart() { return Start; }
int32 GetEnd() { return Start + ComputeSize(); }
private:
// in bytes
int32 Start;
// in bytes, 0:not valid, <0:unoccupied, >0:occupied
int32 Size;
};
public:
// constructor
FRangeAllocator(uint32 TotalSize)
{
FRange NewRange;
NewRange.SetUnOccupied(0, TotalSize);
Entries.Add(NewRange);
}
// specified range must be non occupied
void OccupyRange(FRange InRange)
{
check(InRange.IsValid());
check(InRange.IsOccupied());
for(uint32 i = 0, Num = Entries.Num(); i < Num; ++i)
{
FRange& ref = Entries[i];
if(!ref.IsOccupied())
{
int32 OverlapSize = ref.GetEnd() - InRange.GetStart();
if(OverlapSize > 0)
{
int32 FrontCutSize = InRange.GetStart() - ref.GetStart();
// there is some front part we cut off
if(FrontCutSize > 0)
{
FRange NewFrontRange;
NewFrontRange.SetUnOccupied(InRange.GetStart(), ref.ComputeSize() - FrontCutSize);
ref.SetUnOccupied(ref.GetStart(), FrontCutSize);
++i;
// remaining is added behind the found element
Entries.Insert(NewFrontRange, i);
// don't access ref or Num any more - Entries[] might be reallocated
}
check(Entries[i].GetStart() == InRange.GetStart());
int32 BackCutSize = Entries[i].ComputeSize() - InRange.ComputeSize();
// otherwise the range was already occupied or not enough space was left (internal error)
check(BackCutSize >= 0);
// there is some back part we cut off
if(BackCutSize > 0)
{
FRange NewBackRange;
NewBackRange.SetUnOccupied(Entries[i].GetStart() + InRange.ComputeSize(), BackCutSize);
Entries.Insert(NewBackRange, i + 1);
}
Entries[i] = InRange;
return;
}
}
}
}
// @param InSize >0
FRange AllocRange(uint32 InSize)//, uint32 Alignment)
{
check(InSize > 0);
for(uint32 i = 0, Num = Entries.Num(); i < Num; ++i)
{
FRange& ref = Entries[i];
if(!ref.IsOccupied())
{
uint32 RefSize = ref.ComputeSize();
// take the first fitting one - later we could optimize for minimal fragmentation
if(RefSize >= InSize)
{
ref.MakeOccupied(InSize);
FRange Ret = ref;
if(RefSize > InSize)
{
FRange NewRange;
NewRange.SetUnOccupied(ref.GetEnd(), RefSize - InSize);
// remaining is added behind the found element
Entries.Insert(NewRange, i + 1);
}
return Ret;
}
}
}
// nothing found
return FRange();
}
// @param In needs to be what was returned by AllocRange()
void ReleaseRange(FRange In)
{
int32 Index = Entries.Find(In);
check(Index != INDEX_NONE);
FRange& refIndex = Entries[Index];
refIndex.MakeUnOccupied();
Compacten(Index);
}
// for debugging
uint32 GetNumEntries() const { return Entries.Num(); }
// for debugging
uint32 ComputeUnoccupiedSize() const
{
uint32 Ret = 0;
for(uint32 i = 0, Num = Entries.Num(); i < Num; ++i)
{
const FRange& ref = Entries[i];
if(!ref.IsOccupied())
{
uint32 RefSize = ref.ComputeSize();
Ret += RefSize;
}
}
return Ret;
}
private:
// compact unoccupied ranges
void Compacten(uint32 StartIndex)
{
check(!Entries[StartIndex].IsOccupied());
if(StartIndex && !Entries[StartIndex-1].IsOccupied())
{
// Seems we can combine with the element before,
// searching further is not needed as we assume the buffer was compact before the last change.
--StartIndex;
}
uint32 ElementsToRemove = 0;
uint32 SizeGained = 0;
for(uint32 i = StartIndex + 1, Num = Entries.Num(); i < Num; ++i)
{
FRange& ref = Entries[i];
if(!ref.IsOccupied())
{
++ElementsToRemove;
SizeGained += ref.ComputeSize();
}
else
{
break;
}
}
if(ElementsToRemove)
{
Entries.RemoveAt(StartIndex + 1, ElementsToRemove, EAllowShrinking::No);
Entries[StartIndex].ExtendUnoccupied(SizeGained);
}
}
public:
static void Test()
{
// testing code
#if !UE_BUILD_SHIPPING
{
// create
FRangeAllocator A(10);
check(A.GetNumEntries() == 1);
check(A.ComputeUnoccupiedSize() == 10);
// successfully alloc
FRangeAllocator::FRange a = A.AllocRange(3);
check(a.GetStart() == 0);
check(a.GetEnd() == 3);
check(a.IsOccupied());
check(A.GetNumEntries() == 2);
check(A.ComputeUnoccupiedSize() == 7);
// successfully alloc
FRangeAllocator::FRange b = A.AllocRange(4);
check(b.GetStart() == 3);
check(b.GetEnd() == 7);
check(b.IsOccupied());
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 3);
// failed alloc
FRangeAllocator::FRange c = A.AllocRange(4);
check(!c.IsValid());
check(!c.IsOccupied());
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 3);
// successfully alloc
FRangeAllocator::FRange d = A.AllocRange(3);
check(d.GetStart() == 7);
check(d.GetEnd() == 10);
check(d.IsOccupied());
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 0);
A.ReleaseRange(b);
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 4);
A.ReleaseRange(a);
check(A.GetNumEntries() == 2);
check(A.ComputeUnoccupiedSize() == 7);
A.ReleaseRange(d);
check(A.GetNumEntries() == 1);
check(A.ComputeUnoccupiedSize() == 10);
// we are back to a clean start
FRangeAllocator::FRange e = A.AllocRange(10);
check(e.GetStart() == 0);
check(e.GetEnd() == 10);
check(e.IsOccupied());
check(A.GetNumEntries() == 1);
check(A.ComputeUnoccupiedSize() == 0);
A.ReleaseRange(e);
check(A.GetNumEntries() == 1);
check(A.ComputeUnoccupiedSize() == 10);
// we are back to a clean start
// create define range we want to block out
FRangeAllocator::FRange f;
f.SetOccupied(2, 4);
A.OccupyRange(f);
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 6);
FRangeAllocator::FRange g = A.AllocRange(2);
check(g.GetStart() == 0);
check(g.GetEnd() == 2);
check(g.IsOccupied());
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 4);
FRangeAllocator::FRange h = A.AllocRange(4);
check(h.GetStart() == 6);
check(h.GetEnd() == 10);
check(h.IsOccupied());
check(A.GetNumEntries() == 3);
check(A.ComputeUnoccupiedSize() == 0);
}
#endif // !UE_BUILD_SHIPPING
}
private:
// ordered from small to large (for efficient compactening)
TArray<FRange> Entries;
};
extern D3D11RHI_API FD3D11DynamicRHI* GD3D11RHI;